Basic and token authentication support
This commit is contained in:
1
examples/auth/README.md
Normal file
1
examples/auth/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains examples that demonstrate basic and token authentication.
|
||||
31
examples/auth/basic_auth.py
Normal file
31
examples/auth/basic_auth.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from microdot import Microdot
|
||||
from microdot.auth import BasicAuth
|
||||
from pbkdf2 import generate_password_hash, check_password_hash
|
||||
|
||||
|
||||
# this example provides an implementation of the generate_password_hash and
|
||||
# check_password_hash functions that can be used in MicroPython. On CPython
|
||||
# there are many other options for password hashisng so there is no need to use
|
||||
# this custom solution.
|
||||
USERS = {
|
||||
'susan': generate_password_hash('hello'),
|
||||
'david': generate_password_hash('bye'),
|
||||
}
|
||||
app = Microdot()
|
||||
auth = BasicAuth()
|
||||
|
||||
|
||||
@auth.authenticate
|
||||
async def check_credentials(request, username, password):
|
||||
if username in USERS and check_password_hash(USERS[username], password):
|
||||
return username
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@auth
|
||||
async def index(request):
|
||||
return f'Hello, {request.g.current_user}!'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
47
examples/auth/pbkdf2.py
Normal file
47
examples/auth/pbkdf2.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import os
|
||||
import hashlib
|
||||
|
||||
# PBKDF2 secure password hashing algorithm obtained from:
|
||||
# https://codeandlife.com/2023/01/06/how-to-calculate-pbkdf2-hmac-sha256-with-
|
||||
# python,-example-code/
|
||||
|
||||
|
||||
def sha256(b):
|
||||
return hashlib.sha256(b).digest()
|
||||
|
||||
|
||||
def ljust(b, n, f):
|
||||
return b + f * (n - len(b))
|
||||
|
||||
|
||||
def gethmac(key, content):
|
||||
okeypad = bytes(v ^ 0x5c for v in ljust(key, 64, b'\0'))
|
||||
ikeypad = bytes(v ^ 0x36 for v in ljust(key, 64, b'\0'))
|
||||
return sha256(okeypad + sha256(ikeypad + content))
|
||||
|
||||
|
||||
def pbkdf2(pwd, salt, iterations=1000):
|
||||
U = salt + b'\x00\x00\x00\x01'
|
||||
T = bytes(64)
|
||||
for _ in range(iterations):
|
||||
U = gethmac(pwd, U)
|
||||
T = bytes(a ^ b for a, b in zip(U, T))
|
||||
return T
|
||||
|
||||
|
||||
# The number of iterations may need to be adjusted depending on the hardware.
|
||||
# Lower numbers make the password hashing algorithm faster but less secure, so
|
||||
# the largest number that can be tolerated should be used.
|
||||
def generate_password_hash(password, salt=None, iterations=100000):
|
||||
salt = salt or os.urandom(16)
|
||||
dk = pbkdf2(password.encode(), salt, iterations)
|
||||
return f'pbkdf2-hmac-sha256:{salt.hex()}:{iterations}:{dk.hex()}'
|
||||
|
||||
|
||||
def check_password_hash(password_hash, password):
|
||||
algorithm, salt, iterations, dk = password_hash.split(':')
|
||||
iterations = int(iterations)
|
||||
if algorithm != 'pbkdf2-hmac-sha256':
|
||||
return False
|
||||
return pbkdf2(password.encode(), salt=bytes.fromhex(salt),
|
||||
iterations=iterations) == bytes.fromhex(dk)
|
||||
26
examples/auth/token_auth.py
Normal file
26
examples/auth/token_auth.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from microdot import Microdot
|
||||
from microdot.auth import TokenAuth
|
||||
|
||||
app = Microdot()
|
||||
auth = TokenAuth()
|
||||
|
||||
TOKENS = {
|
||||
'susan-token': 'susan',
|
||||
'david-token': 'david',
|
||||
}
|
||||
|
||||
|
||||
@auth.authenticate
|
||||
async def check_token(request, token):
|
||||
if token in TOKENS:
|
||||
return TOKENS[token]
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@auth
|
||||
async def index(request):
|
||||
return f'Hello, {request.g.current_user}!'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
Reference in New Issue
Block a user