format and lint orm
This commit is contained in:
@@ -16,119 +16,126 @@ from settings import JWT_AUTH_HEADER, EMAIL_TOKEN_LIFE_SPAN
|
||||
|
||||
|
||||
class _Authenticate:
|
||||
@classmethod
|
||||
async def verify(cls, token: str):
|
||||
"""
|
||||
Rules for a token to be valid.
|
||||
1. token format is legal &&
|
||||
token exists in redis database &&
|
||||
token is not expired
|
||||
2. token format is legal &&
|
||||
token exists in redis database &&
|
||||
token is expired &&
|
||||
token is of specified type
|
||||
"""
|
||||
try:
|
||||
payload = JWTCodec.decode(token)
|
||||
except ExpiredSignatureError:
|
||||
payload = JWTCodec.decode(token, verify_exp=False)
|
||||
if not await cls.exists(payload.user_id, token):
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
if payload.device == "mobile": # noqa
|
||||
"we cat set mobile token to be valid forever"
|
||||
return payload
|
||||
except DecodeError as e:
|
||||
raise InvalidToken("token format error") from e
|
||||
else:
|
||||
if not await cls.exists(payload.user_id, token):
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
return payload
|
||||
@classmethod
|
||||
async def verify(cls, token: str):
|
||||
"""
|
||||
Rules for a token to be valid.
|
||||
1. token format is legal &&
|
||||
token exists in redis database &&
|
||||
token is not expired
|
||||
2. token format is legal &&
|
||||
token exists in redis database &&
|
||||
token is expired &&
|
||||
token is of specified type
|
||||
"""
|
||||
try:
|
||||
payload = JWTCodec.decode(token)
|
||||
except ExpiredSignatureError:
|
||||
payload = JWTCodec.decode(token, verify_exp=False)
|
||||
if not await cls.exists(payload.user_id, token):
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
if payload.device == "mobile": # noqa
|
||||
"we cat set mobile token to be valid forever"
|
||||
return payload
|
||||
except DecodeError as e:
|
||||
raise InvalidToken("token format error") from e
|
||||
else:
|
||||
if not await cls.exists(payload.user_id, token):
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
return payload
|
||||
|
||||
@classmethod
|
||||
async def exists(cls, user_id, token):
|
||||
return await TokenStorage.exist(f"{user_id}-{token}")
|
||||
@classmethod
|
||||
async def exists(cls, user_id, token):
|
||||
return await TokenStorage.exist(f"{user_id}-{token}")
|
||||
|
||||
|
||||
class JWTAuthenticate(AuthenticationBackend):
|
||||
async def authenticate(
|
||||
self, request: HTTPConnection
|
||||
) -> Optional[Tuple[AuthCredentials, AuthUser]]:
|
||||
if JWT_AUTH_HEADER not in request.headers:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
async def authenticate(
|
||||
self, request: HTTPConnection
|
||||
) -> Optional[Tuple[AuthCredentials, AuthUser]]:
|
||||
if JWT_AUTH_HEADER not in request.headers:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
|
||||
token = request.headers[JWT_AUTH_HEADER]
|
||||
try:
|
||||
payload = await _Authenticate.verify(token)
|
||||
except Exception as exc:
|
||||
return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser(user_id=None)
|
||||
|
||||
if payload is None:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
token = request.headers[JWT_AUTH_HEADER]
|
||||
try:
|
||||
payload = await _Authenticate.verify(token)
|
||||
except Exception as exc:
|
||||
return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser(
|
||||
user_id=None
|
||||
)
|
||||
|
||||
if not payload.device in ("pc", "mobile"):
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
if payload is None:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
|
||||
user = await UserStorage.get_user(payload.user_id)
|
||||
if not user:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
if not payload.device in ("pc", "mobile"):
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
|
||||
user = await UserStorage.get_user(payload.user_id)
|
||||
if not user:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
|
||||
scopes = await user.get_permission()
|
||||
return (
|
||||
AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True),
|
||||
user,
|
||||
)
|
||||
|
||||
scopes = await user.get_permission()
|
||||
return AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True), user
|
||||
|
||||
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 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:
|
||||
raise InvalidToken("invalid token")
|
||||
if payload.device != "email":
|
||||
raise InvalidToken("invalid token")
|
||||
with local_session() as session:
|
||||
user = session.query(User).filter_by(id=payload.user_id).first()
|
||||
if not user:
|
||||
raise Exception("user not exist")
|
||||
if not user.emailConfirmed:
|
||||
user.emailConfirmed = True
|
||||
session.commit()
|
||||
auth_token = await Authorize.authorize(user)
|
||||
return (auth_token, user)
|
||||
|
||||
@staticmethod
|
||||
async def authenticate(token):
|
||||
payload = await _Authenticate.verify(token)
|
||||
if payload is None:
|
||||
raise InvalidToken("invalid token")
|
||||
if payload.device != "email":
|
||||
raise InvalidToken("invalid token")
|
||||
with local_session() as session:
|
||||
user = session.query(User).filter_by(id=payload.user_id).first()
|
||||
if not user:
|
||||
raise Exception("user not exist")
|
||||
if not user.emailConfirmed:
|
||||
user.emailConfirmed = True
|
||||
session.commit()
|
||||
auth_token = await Authorize.authorize(user)
|
||||
return (auth_token, user)
|
||||
|
||||
class ResetPassword:
|
||||
@staticmethod
|
||||
async def get_reset_token(user):
|
||||
exp = datetime.utcnow() + timedelta(seconds=EMAIL_TOKEN_LIFE_SPAN)
|
||||
token = JWTCodec.encode(user, exp=exp, device="pc")
|
||||
await TokenStorage.save(f"{user.id}-reset-{token}", EMAIL_TOKEN_LIFE_SPAN, True)
|
||||
return token
|
||||
@staticmethod
|
||||
async def get_reset_token(user):
|
||||
exp = datetime.utcnow() + timedelta(seconds=EMAIL_TOKEN_LIFE_SPAN)
|
||||
token = JWTCodec.encode(user, exp=exp, device="pc")
|
||||
await TokenStorage.save(f"{user.id}-reset-{token}", EMAIL_TOKEN_LIFE_SPAN, True)
|
||||
return token
|
||||
|
||||
@staticmethod
|
||||
async def verify(token):
|
||||
try:
|
||||
payload = JWTCodec.decode(token)
|
||||
except ExpiredSignatureError:
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
except DecodeError as e:
|
||||
raise InvalidToken("token format error") from e
|
||||
else:
|
||||
if not await TokenStorage.exist(f"{payload.user_id}-reset-{token}"):
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
@staticmethod
|
||||
async def verify(token):
|
||||
try:
|
||||
payload = JWTCodec.decode(token)
|
||||
except ExpiredSignatureError:
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
except DecodeError as e:
|
||||
raise InvalidToken("token format error") from e
|
||||
else:
|
||||
if not await TokenStorage.exist(f"{payload.user_id}-reset-{token}"):
|
||||
raise InvalidToken("Login expired, please login again")
|
||||
|
||||
return payload.user_id
|
||||
|
||||
return payload.user_id
|
||||
|
||||
def login_required(func):
|
||||
@wraps(func)
|
||||
async def wrap(parent, info: GraphQLResolveInfo, *args, **kwargs):
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
if not auth.logged_in:
|
||||
return {"error" : auth.error_message or "Please login"}
|
||||
return await func(parent, info, *args, **kwargs)
|
||||
return wrap
|
||||
@wraps(func)
|
||||
async def wrap(parent, info: GraphQLResolveInfo, *args, **kwargs):
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
if not auth.logged_in:
|
||||
return {"error": auth.error_message or "Please login"}
|
||||
return await func(parent, info, *args, **kwargs)
|
||||
|
||||
return wrap
|
||||
|
@@ -5,38 +5,41 @@ from base.redis import redis
|
||||
from settings import JWT_LIFE_SPAN
|
||||
from auth.validations import User
|
||||
|
||||
class TokenStorage:
|
||||
@staticmethod
|
||||
async def save(token_key, life_span, auto_delete=True):
|
||||
await redis.execute("SET", token_key, "True")
|
||||
if auto_delete:
|
||||
expire_at = (datetime.now() + timedelta(seconds=life_span)).timestamp()
|
||||
await redis.execute("EXPIREAT", token_key, int(expire_at))
|
||||
|
||||
@staticmethod
|
||||
async def exist(token_key):
|
||||
return await redis.execute("GET", token_key)
|
||||
class TokenStorage:
|
||||
@staticmethod
|
||||
async def save(token_key, life_span, auto_delete=True):
|
||||
await redis.execute("SET", token_key, "True")
|
||||
if auto_delete:
|
||||
expire_at = (datetime.now() + timedelta(seconds=life_span)).timestamp()
|
||||
await redis.execute("EXPIREAT", token_key, int(expire_at))
|
||||
|
||||
@staticmethod
|
||||
async def exist(token_key):
|
||||
return await redis.execute("GET", token_key)
|
||||
|
||||
|
||||
class Authorize:
|
||||
@staticmethod
|
||||
async def authorize(user: User, device: str = "pc", life_span = JWT_LIFE_SPAN, auto_delete=True) -> str:
|
||||
exp = datetime.utcnow() + timedelta(seconds=life_span)
|
||||
token = JWTCodec.encode(user, exp=exp, device=device)
|
||||
await TokenStorage.save(f"{user.id}-{token}", life_span, auto_delete)
|
||||
return token
|
||||
@staticmethod
|
||||
async def authorize(
|
||||
user: User, device: str = "pc", life_span=JWT_LIFE_SPAN, auto_delete=True
|
||||
) -> str:
|
||||
exp = datetime.utcnow() + timedelta(seconds=life_span)
|
||||
token = JWTCodec.encode(user, exp=exp, device=device)
|
||||
await TokenStorage.save(f"{user.id}-{token}", life_span, auto_delete)
|
||||
return token
|
||||
|
||||
@staticmethod
|
||||
async def revoke(token: str) -> bool:
|
||||
try:
|
||||
payload = JWTCodec.decode(token)
|
||||
except: # noqa
|
||||
pass
|
||||
else:
|
||||
await redis.execute("DEL", f"{payload.user_id}-{token}")
|
||||
return True
|
||||
@staticmethod
|
||||
async def revoke(token: str) -> bool:
|
||||
try:
|
||||
payload = JWTCodec.decode(token)
|
||||
except: # noqa
|
||||
pass
|
||||
else:
|
||||
await redis.execute("DEL", f"{payload.user_id}-{token}")
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
async def revoke_all(user: User):
|
||||
tokens = await redis.execute("KEYS", f"{user.id}-*")
|
||||
await redis.execute("DEL", *tokens)
|
||||
@staticmethod
|
||||
async def revoke_all(user: User):
|
||||
tokens = await redis.execute("KEYS", f"{user.id}-*")
|
||||
await redis.execute("DEL", *tokens)
|
||||
|
108
auth/email.py
108
auth/email.py
@@ -2,71 +2,83 @@ import requests
|
||||
from starlette.responses import RedirectResponse
|
||||
from auth.authenticate import EmailAuthenticate, ResetPassword
|
||||
from base.orm import local_session
|
||||
from settings import BACKEND_URL, MAILGUN_API_KEY, MAILGUN_DOMAIN, RESET_PWD_URL, \
|
||||
CONFIRM_EMAIL_URL, ERROR_URL_ON_FRONTEND
|
||||
from settings import (
|
||||
BACKEND_URL,
|
||||
MAILGUN_API_KEY,
|
||||
MAILGUN_DOMAIN,
|
||||
RESET_PWD_URL,
|
||||
CONFIRM_EMAIL_URL,
|
||||
ERROR_URL_ON_FRONTEND,
|
||||
)
|
||||
|
||||
MAILGUN_API_URL = "https://api.mailgun.net/v3/%s/messages" % (MAILGUN_DOMAIN)
|
||||
MAILGUN_FROM = "discours.io <noreply@%s>" % (MAILGUN_DOMAIN)
|
||||
|
||||
AUTH_URL = "%s/email_authorize" % (BACKEND_URL)
|
||||
|
||||
email_templates = {"confirm_email" : "", "auth_email" : "", "reset_password_email" : ""}
|
||||
email_templates = {"confirm_email": "", "auth_email": "", "reset_password_email": ""}
|
||||
|
||||
|
||||
def load_email_templates():
|
||||
for name in email_templates:
|
||||
filename = "auth/templates/%s.tmpl" % name
|
||||
with open(filename) as f:
|
||||
email_templates[name] = f.read()
|
||||
print("[auth.email] templates loaded")
|
||||
for name in email_templates:
|
||||
filename = "auth/templates/%s.tmpl" % name
|
||||
with open(filename) as f:
|
||||
email_templates[name] = f.read()
|
||||
print("[auth.email] templates loaded")
|
||||
|
||||
|
||||
async def send_confirm_email(user):
|
||||
text = email_templates["confirm_email"]
|
||||
token = await EmailAuthenticate.get_email_token(user)
|
||||
await send_email(user, AUTH_URL, text, token)
|
||||
text = email_templates["confirm_email"]
|
||||
token = await EmailAuthenticate.get_email_token(user)
|
||||
await send_email(user, AUTH_URL, text, token)
|
||||
|
||||
|
||||
async def send_auth_email(user):
|
||||
text = email_templates["auth_email"]
|
||||
token = await EmailAuthenticate.get_email_token(user)
|
||||
await send_email(user, AUTH_URL, text, token)
|
||||
text = email_templates["auth_email"]
|
||||
token = await EmailAuthenticate.get_email_token(user)
|
||||
await send_email(user, AUTH_URL, text, token)
|
||||
|
||||
|
||||
async def send_reset_password_email(user):
|
||||
text = email_templates["reset_password_email"]
|
||||
token = await ResetPassword.get_reset_token(user)
|
||||
await send_email(user, RESET_PWD_URL, text, token)
|
||||
text = email_templates["reset_password_email"]
|
||||
token = await ResetPassword.get_reset_token(user)
|
||||
await send_email(user, RESET_PWD_URL, text, token)
|
||||
|
||||
|
||||
async def send_email(user, url, text, token):
|
||||
to = "%s <%s>" % (user.username, user.email)
|
||||
url_with_token = "%s?token=%s" % (url, token)
|
||||
text = text % (url_with_token)
|
||||
response = requests.post(
|
||||
MAILGUN_API_URL,
|
||||
auth = ("api", MAILGUN_API_KEY),
|
||||
data = {
|
||||
"from": MAILGUN_FROM,
|
||||
"to": to,
|
||||
"subject": "authorize log in",
|
||||
"html": text
|
||||
}
|
||||
)
|
||||
response.raise_for_status()
|
||||
to = "%s <%s>" % (user.username, user.email)
|
||||
url_with_token = "%s?token=%s" % (url, token)
|
||||
text = text % (url_with_token)
|
||||
response = requests.post(
|
||||
MAILGUN_API_URL,
|
||||
auth=("api", MAILGUN_API_KEY),
|
||||
data={
|
||||
"from": MAILGUN_FROM,
|
||||
"to": to,
|
||||
"subject": "authorize log in",
|
||||
"html": text,
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
async def email_authorize(request):
|
||||
token = request.query_params.get('token')
|
||||
if not token:
|
||||
url_with_error = "%s?error=%s" % (ERROR_URL_ON_FRONTEND, "INVALID_TOKEN")
|
||||
return RedirectResponse(url = url_with_error)
|
||||
token = request.query_params.get("token")
|
||||
if not token:
|
||||
url_with_error = "%s?error=%s" % (ERROR_URL_ON_FRONTEND, "INVALID_TOKEN")
|
||||
return RedirectResponse(url=url_with_error)
|
||||
|
||||
try:
|
||||
auth_token, user = await EmailAuthenticate.authenticate(token)
|
||||
except:
|
||||
url_with_error = "%s?error=%s" % (ERROR_URL_ON_FRONTEND, "INVALID_TOKEN")
|
||||
return RedirectResponse(url = url_with_error)
|
||||
|
||||
if not user.emailConfirmed:
|
||||
with local_session() as session:
|
||||
user.emailConfirmed = True
|
||||
session.commit()
|
||||
try:
|
||||
auth_token, user = await EmailAuthenticate.authenticate(token)
|
||||
except:
|
||||
url_with_error = "%s?error=%s" % (ERROR_URL_ON_FRONTEND, "INVALID_TOKEN")
|
||||
return RedirectResponse(url=url_with_error)
|
||||
|
||||
response = RedirectResponse(url = CONFIRM_EMAIL_URL)
|
||||
response.set_cookie("token", auth_token)
|
||||
return response
|
||||
if not user.emailConfirmed:
|
||||
with local_session() as session:
|
||||
user.emailConfirmed = True
|
||||
session.commit()
|
||||
|
||||
response = RedirectResponse(url=CONFIRM_EMAIL_URL)
|
||||
response.set_cookie("token", auth_token)
|
||||
return response
|
||||
|
@@ -8,26 +8,32 @@ from sqlalchemy import or_
|
||||
|
||||
|
||||
class Identity:
|
||||
@staticmethod
|
||||
def identity(orm_user: OrmUser, password: str) -> User:
|
||||
user = User(**orm_user.dict())
|
||||
if user.password is None:
|
||||
raise InvalidPassword("Wrong user password")
|
||||
if not Password.verify(password, user.password):
|
||||
raise InvalidPassword("Wrong user password")
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def identity_oauth(input) -> User:
|
||||
with local_session() as session:
|
||||
user = session.query(OrmUser).filter(
|
||||
or_(OrmUser.oauth == input["oauth"], OrmUser.email == input["email"])
|
||||
).first()
|
||||
if not user:
|
||||
user = OrmUser.create(**input)
|
||||
if not user.oauth:
|
||||
user.oauth = input["oauth"]
|
||||
session.commit()
|
||||
@staticmethod
|
||||
def identity(orm_user: OrmUser, password: str) -> User:
|
||||
user = User(**orm_user.dict())
|
||||
if user.password is None:
|
||||
raise InvalidPassword("Wrong user password")
|
||||
if not Password.verify(password, user.password):
|
||||
raise InvalidPassword("Wrong user password")
|
||||
return user
|
||||
|
||||
user = User(**user.dict())
|
||||
return user
|
||||
@staticmethod
|
||||
def identity_oauth(input) -> User:
|
||||
with local_session() as session:
|
||||
user = (
|
||||
session.query(OrmUser)
|
||||
.filter(
|
||||
or_(
|
||||
OrmUser.oauth == input["oauth"], OrmUser.email == input["email"]
|
||||
)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if not user:
|
||||
user = OrmUser.create(**input)
|
||||
if not user.oauth:
|
||||
user.oauth = input["oauth"]
|
||||
session.commit()
|
||||
|
||||
user = User(**user.dict())
|
||||
return user
|
||||
|
@@ -5,17 +5,22 @@ from auth.validations import PayLoad, User
|
||||
|
||||
|
||||
class JWTCodec:
|
||||
@staticmethod
|
||||
def encode(user: User, exp: datetime, device: str = "pc") -> str:
|
||||
payload = {"user_id": user.id, "device": device, "exp": exp, "iat": datetime.utcnow()}
|
||||
return jwt.encode(payload, JWT_SECRET_KEY, JWT_ALGORITHM)
|
||||
@staticmethod
|
||||
def encode(user: User, exp: datetime, device: str = "pc") -> str:
|
||||
payload = {
|
||||
"user_id": user.id,
|
||||
"device": device,
|
||||
"exp": exp,
|
||||
"iat": datetime.utcnow(),
|
||||
}
|
||||
return jwt.encode(payload, JWT_SECRET_KEY, JWT_ALGORITHM)
|
||||
|
||||
@staticmethod
|
||||
def decode(token: str, verify_exp: bool = True) -> PayLoad:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
key=JWT_SECRET_KEY,
|
||||
options={"verify_exp": verify_exp},
|
||||
algorithms=[JWT_ALGORITHM],
|
||||
)
|
||||
return PayLoad(**payload)
|
||||
@staticmethod
|
||||
def decode(token: str, verify_exp: bool = True) -> PayLoad:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
key=JWT_SECRET_KEY,
|
||||
options={"verify_exp": verify_exp},
|
||||
algorithms=[JWT_ALGORITHM],
|
||||
)
|
||||
return PayLoad(**payload)
|
||||
|
113
auth/oauth.py
113
auth/oauth.py
@@ -8,79 +8,84 @@ from settings import OAUTH_CLIENTS, BACKEND_URL, OAUTH_CALLBACK_URL
|
||||
oauth = OAuth()
|
||||
|
||||
oauth.register(
|
||||
name='facebook',
|
||||
client_id=OAUTH_CLIENTS["FACEBOOK"]["id"],
|
||||
client_secret=OAUTH_CLIENTS["FACEBOOK"]["key"],
|
||||
access_token_url='https://graph.facebook.com/v11.0/oauth/access_token',
|
||||
access_token_params=None,
|
||||
authorize_url='https://www.facebook.com/v11.0/dialog/oauth',
|
||||
authorize_params=None,
|
||||
api_base_url='https://graph.facebook.com/',
|
||||
client_kwargs={'scope': 'public_profile email'},
|
||||
name="facebook",
|
||||
client_id=OAUTH_CLIENTS["FACEBOOK"]["id"],
|
||||
client_secret=OAUTH_CLIENTS["FACEBOOK"]["key"],
|
||||
access_token_url="https://graph.facebook.com/v11.0/oauth/access_token",
|
||||
access_token_params=None,
|
||||
authorize_url="https://www.facebook.com/v11.0/dialog/oauth",
|
||||
authorize_params=None,
|
||||
api_base_url="https://graph.facebook.com/",
|
||||
client_kwargs={"scope": "public_profile email"},
|
||||
)
|
||||
|
||||
oauth.register(
|
||||
name='github',
|
||||
client_id=OAUTH_CLIENTS["GITHUB"]["id"],
|
||||
client_secret=OAUTH_CLIENTS["GITHUB"]["key"],
|
||||
access_token_url='https://github.com/login/oauth/access_token',
|
||||
access_token_params=None,
|
||||
authorize_url='https://github.com/login/oauth/authorize',
|
||||
authorize_params=None,
|
||||
api_base_url='https://api.github.com/',
|
||||
client_kwargs={'scope': 'user:email'},
|
||||
name="github",
|
||||
client_id=OAUTH_CLIENTS["GITHUB"]["id"],
|
||||
client_secret=OAUTH_CLIENTS["GITHUB"]["key"],
|
||||
access_token_url="https://github.com/login/oauth/access_token",
|
||||
access_token_params=None,
|
||||
authorize_url="https://github.com/login/oauth/authorize",
|
||||
authorize_params=None,
|
||||
api_base_url="https://api.github.com/",
|
||||
client_kwargs={"scope": "user:email"},
|
||||
)
|
||||
|
||||
oauth.register(
|
||||
name='google',
|
||||
client_id=OAUTH_CLIENTS["GOOGLE"]["id"],
|
||||
client_secret=OAUTH_CLIENTS["GOOGLE"]["key"],
|
||||
server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
|
||||
client_kwargs={'scope': 'openid email profile'}
|
||||
name="google",
|
||||
client_id=OAUTH_CLIENTS["GOOGLE"]["id"],
|
||||
client_secret=OAUTH_CLIENTS["GOOGLE"]["key"],
|
||||
server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
|
||||
client_kwargs={"scope": "openid email profile"},
|
||||
)
|
||||
|
||||
|
||||
async def google_profile(client, request, token):
|
||||
profile = await client.parse_id_token(request, token)
|
||||
profile["id"] = profile["sub"]
|
||||
return profile
|
||||
profile = await client.parse_id_token(request, token)
|
||||
profile["id"] = profile["sub"]
|
||||
return profile
|
||||
|
||||
|
||||
async def facebook_profile(client, request, token):
|
||||
profile = await client.get('me?fields=name,id,email', token=token)
|
||||
return profile.json()
|
||||
profile = await client.get("me?fields=name,id,email", token=token)
|
||||
return profile.json()
|
||||
|
||||
|
||||
async def github_profile(client, request, token):
|
||||
profile = await client.get('user', token=token)
|
||||
return profile.json()
|
||||
profile = await client.get("user", token=token)
|
||||
return profile.json()
|
||||
|
||||
|
||||
profile_callbacks = {
|
||||
"google" : google_profile,
|
||||
"facebook" : facebook_profile,
|
||||
"github" : github_profile
|
||||
"google": google_profile,
|
||||
"facebook": facebook_profile,
|
||||
"github": github_profile,
|
||||
}
|
||||
|
||||
|
||||
async def oauth_login(request):
|
||||
provider = request.path_params['provider']
|
||||
request.session['provider'] = provider
|
||||
client = oauth.create_client(provider)
|
||||
redirect_uri = "%s/%s" % (BACKEND_URL, 'oauth_authorize')
|
||||
return await client.authorize_redirect(request, redirect_uri)
|
||||
provider = request.path_params["provider"]
|
||||
request.session["provider"] = provider
|
||||
client = oauth.create_client(provider)
|
||||
redirect_uri = "%s/%s" % (BACKEND_URL, "oauth_authorize")
|
||||
return await client.authorize_redirect(request, redirect_uri)
|
||||
|
||||
|
||||
async def oauth_authorize(request):
|
||||
provider = request.session['provider']
|
||||
client = oauth.create_client(provider)
|
||||
token = await client.authorize_access_token(request)
|
||||
get_profile = profile_callbacks[provider]
|
||||
profile = await get_profile(client, request, token)
|
||||
user_oauth_info = "%s:%s" % (provider, profile["id"])
|
||||
user_input = {
|
||||
"oauth" : user_oauth_info,
|
||||
"email" : profile["email"],
|
||||
"username" : profile["name"]
|
||||
}
|
||||
user = Identity.identity_oauth(user_input)
|
||||
token = await Authorize.authorize(user, device="pc")
|
||||
provider = request.session["provider"]
|
||||
client = oauth.create_client(provider)
|
||||
token = await client.authorize_access_token(request)
|
||||
get_profile = profile_callbacks[provider]
|
||||
profile = await get_profile(client, request, token)
|
||||
user_oauth_info = "%s:%s" % (provider, profile["id"])
|
||||
user_input = {
|
||||
"oauth": user_oauth_info,
|
||||
"email": profile["email"],
|
||||
"username": profile["name"],
|
||||
}
|
||||
user = Identity.identity_oauth(user_input)
|
||||
token = await Authorize.authorize(user, device="pc")
|
||||
|
||||
response = RedirectResponse(url = OAUTH_CALLBACK_URL)
|
||||
response.set_cookie("token", token)
|
||||
return response
|
||||
response = RedirectResponse(url=OAUTH_CALLBACK_URL)
|
||||
response.set_cookie("token", token)
|
||||
return response
|
||||
|
Reference in New Issue
Block a user