auth via email
This commit is contained in:
@@ -8,10 +8,11 @@ from starlette.requests import HTTPConnection
|
||||
|
||||
from auth.credentials import AuthCredentials, AuthUser
|
||||
from auth.token import Token
|
||||
from auth.authorize import Authorize
|
||||
from exceptions import InvalidToken, OperationNotAllowed
|
||||
from orm import User
|
||||
from redis import redis
|
||||
from settings import JWT_AUTH_HEADER
|
||||
from settings import JWT_AUTH_HEADER, EMAIL_TOKEN_LIFE_SPAN
|
||||
|
||||
|
||||
class _Authenticate:
|
||||
@@ -68,6 +69,25 @@ class JWTAuthenticate(AuthenticationBackend):
|
||||
scopes = User.get_permission(user_id=payload.user_id)
|
||||
return AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True), AuthUser(user_id=payload.user_id)
|
||||
|
||||
class EmailAuthenticate:
|
||||
@staticmethod
|
||||
async def get_email_token(user):
|
||||
token = await Authorize.authorize(
|
||||
user,
|
||||
device="email",
|
||||
life_span=EMAIL_TOKEN_LIFE_SPAN
|
||||
)
|
||||
return token
|
||||
|
||||
@staticmethod
|
||||
async def authenticate(token):
|
||||
payload = await _Authenticate.verify(token)
|
||||
if payload is None:
|
||||
return
|
||||
if payload.device != "email":
|
||||
return;
|
||||
auth_token = Authorize.authorize(payload.user)
|
||||
return (auth_token, payload.user)
|
||||
|
||||
def login_required(func):
|
||||
@wraps(func)
|
||||
|
@@ -8,14 +8,14 @@ from auth.validations import User
|
||||
|
||||
class Authorize:
|
||||
@staticmethod
|
||||
async def authorize(user: User, device: str = "pc", auto_delete=True) -> str:
|
||||
async def authorize(user: User, device: str = "pc", life_span = JWT_LIFE_SPAN, auto_delete=True) -> str:
|
||||
"""
|
||||
:param user:
|
||||
:param device:
|
||||
:param auto_delete: Whether the expiration is automatically deleted, the default is True
|
||||
:return:
|
||||
"""
|
||||
exp = datetime.utcnow() + timedelta(seconds=JWT_LIFE_SPAN)
|
||||
exp = datetime.utcnow() + timedelta(seconds=life_span)
|
||||
token = Token.encode(user, exp=exp, device=device)
|
||||
await redis.execute("SET", f"{user.id}-{token}", "True")
|
||||
if auto_delete:
|
||||
@@ -37,13 +37,3 @@ class Authorize:
|
||||
async def revoke_all(user: User):
|
||||
tokens = await redis.execute("KEYS", f"{user.id}-*")
|
||||
await redis.execute("DEL", *tokens)
|
||||
|
||||
@staticmethod
|
||||
async def confirm(token: str):
|
||||
try:
|
||||
# NOTE: auth_token and email_token are different
|
||||
payload = Token.decode(token) # TODO: check to decode here the proper way
|
||||
auth_token = self.authorize(payload.user)
|
||||
return auth_token, payload.user
|
||||
except:
|
||||
pass
|
||||
|
27
auth/email.py
Normal file
27
auth/email.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import requests
|
||||
|
||||
from auth.authenticate import EmailAuthenticate
|
||||
|
||||
from settings import MAILGUN_API_KEY, MAILGUN_DOMAIN
|
||||
|
||||
MAILGUN_API_URL = "https://api.mailgun.net/v3/%s/messages" % (MAILGUN_DOMAIN)
|
||||
MAILGUN_FROM = "postmaster <postmaster@%s>" % (MAILGUN_DOMAIN)
|
||||
|
||||
AUTH_URL = "https://localhost:8080/auth"
|
||||
|
||||
async def send_auth_email(user):
|
||||
token = await EmailAuthenticate.get_email_token(user)
|
||||
|
||||
to = "%s <%s>" % (user.username, user.email)
|
||||
text = "%s&token=%s" % (AUTH_URL, token)
|
||||
response = requests.post(
|
||||
MAILGUN_API_URL,
|
||||
auth = ("api", MAILGUN_API_KEY),
|
||||
data = {
|
||||
"from": MAILGUN_FROM,
|
||||
"to": to,
|
||||
"subject": "authorize log in",
|
||||
"text": text
|
||||
}
|
||||
)
|
||||
response.raise_for_status()
|
@@ -64,5 +64,5 @@ async def oauth_authorize(request):
|
||||
"username" : profile["name"]
|
||||
}
|
||||
user = Identity.identity_oauth(user_input)
|
||||
token = await Authorize.authorize(user, device="pc", auto_delete=False)
|
||||
token = await Authorize.authorize(user, device="pc")
|
||||
return PlainTextResponse(token)
|
||||
|
Reference in New Issue
Block a user