Feature/google oauth (#106)
google oauth --------- Co-authored-by: Igor Lobanov <igor.lobanov@onetwotrip.com>
This commit is contained in:
parent
2679b2c873
commit
0e9f0b0682
|
@ -3,7 +3,6 @@ from hashlib import sha256
|
||||||
|
|
||||||
from jwt import DecodeError, ExpiredSignatureError
|
from jwt import DecodeError, ExpiredSignatureError
|
||||||
from passlib.hash import bcrypt
|
from passlib.hash import bcrypt
|
||||||
from sqlalchemy import or_
|
|
||||||
|
|
||||||
from auth.jwtcodec import JWTCodec
|
from auth.jwtcodec import JWTCodec
|
||||||
from auth.tokenstorage import TokenStorage
|
from auth.tokenstorage import TokenStorage
|
||||||
|
@ -11,7 +10,6 @@ from auth.tokenstorage import TokenStorage
|
||||||
# from base.exceptions import InvalidPassword, InvalidToken
|
# from base.exceptions import InvalidPassword, InvalidToken
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from orm import User
|
from orm import User
|
||||||
from validations.auth import AuthInput
|
|
||||||
|
|
||||||
|
|
||||||
class Password:
|
class Password:
|
||||||
|
@ -65,20 +63,13 @@ class Identity:
|
||||||
return user
|
return user
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def oauth(inp: AuthInput) -> User:
|
def oauth(inp) -> User:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
user = (
|
user = session.query(User).filter(User.email == inp["email"]).first()
|
||||||
session.query(User)
|
|
||||||
.filter(or_(User.oauth == inp["oauth"], User.email == inp["email"]))
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
if not user:
|
if not user:
|
||||||
user = User.create(**inp)
|
user = User.create(**inp, emailConfirmed=True)
|
||||||
if not user.oauth:
|
|
||||||
user.oauth = inp["oauth"]
|
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
user = User(**user.dict())
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -33,16 +33,25 @@ oauth.register(
|
||||||
|
|
||||||
oauth.register(
|
oauth.register(
|
||||||
name="google",
|
name="google",
|
||||||
client_id=OAUTH_CLIENTS["GOOGLE"]["id"],
|
# client_id=OAUTH_CLIENTS["GOOGLE"]["id"],
|
||||||
client_secret=OAUTH_CLIENTS["GOOGLE"]["key"],
|
# client_secret=OAUTH_CLIENTS["GOOGLE"]["key"],
|
||||||
|
client_id="648983473866-2hd6v2eqqk6hhqabfhuqq2slb2fkfvve.apps.googleusercontent.com",
|
||||||
|
client_secret="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",
|
||||||
server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
|
server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
|
||||||
client_kwargs={"scope": "openid email profile"},
|
client_kwargs={"scope": "openid email profile"},
|
||||||
|
authorize_state="test",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def google_profile(client, request, token):
|
async def google_profile(client, request, token):
|
||||||
profile = await client.parse_id_token(request, token)
|
userinfo = token["userinfo"]
|
||||||
profile["id"] = profile["sub"]
|
|
||||||
|
profile = {"name": userinfo["name"], "email": userinfo["email"], "id": userinfo["sub"]}
|
||||||
|
|
||||||
|
if userinfo["picture"]:
|
||||||
|
userpic = userinfo["picture"].replace("=s96", "=s600")
|
||||||
|
profile["userpic"] = userpic
|
||||||
|
|
||||||
return profile
|
return profile
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +76,8 @@ async def oauth_login(request):
|
||||||
provider = request.path_params["provider"]
|
provider = request.path_params["provider"]
|
||||||
request.session["provider"] = provider
|
request.session["provider"] = provider
|
||||||
client = oauth.create_client(provider)
|
client = oauth.create_client(provider)
|
||||||
redirect_uri = "https://v2.discours.io/oauth-authorize"
|
# redirect_uri = "http://v2.discours.io/oauth-authorize"
|
||||||
|
redirect_uri = "http://localhost:8080/oauth-authorize"
|
||||||
return await client.authorize_redirect(request, redirect_uri)
|
return await client.authorize_redirect(request, redirect_uri)
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,6 +92,7 @@ async def oauth_authorize(request):
|
||||||
"oauth": user_oauth_info,
|
"oauth": user_oauth_info,
|
||||||
"email": profile["email"],
|
"email": profile["email"],
|
||||||
"username": profile["name"],
|
"username": profile["name"],
|
||||||
|
"userpic": profile["userpic"],
|
||||||
}
|
}
|
||||||
user = Identity.oauth(user_input)
|
user = Identity.oauth(user_input)
|
||||||
session_token = await TokenStorage.create_session(user)
|
session_token = await TokenStorage.create_session(user)
|
||||||
|
|
3
main.py
3
main.py
|
@ -16,7 +16,6 @@ from auth.oauth import oauth_authorize, oauth_login
|
||||||
from base.redis import redis
|
from base.redis import redis
|
||||||
from base.resolvers import resolvers
|
from base.resolvers import resolvers
|
||||||
from orm import init_tables
|
from orm import init_tables
|
||||||
from resolvers.auth import confirm_email_handler
|
|
||||||
from resolvers.upload import upload_handler
|
from resolvers.upload import upload_handler
|
||||||
from services.main import storages_init
|
from services.main import storages_init
|
||||||
from services.notifications.notification_service import notification_service
|
from services.notifications.notification_service import notification_service
|
||||||
|
@ -71,10 +70,8 @@ async def shutdown():
|
||||||
|
|
||||||
|
|
||||||
routes = [
|
routes = [
|
||||||
# Route("/messages", endpoint=sse_messages),
|
|
||||||
Route("/oauth/{provider}", endpoint=oauth_login),
|
Route("/oauth/{provider}", endpoint=oauth_login),
|
||||||
Route("/oauth-authorize", endpoint=oauth_authorize),
|
Route("/oauth-authorize", endpoint=oauth_authorize),
|
||||||
Route("/confirm/{token}", endpoint=confirm_email_handler),
|
|
||||||
Route("/upload", endpoint=upload_handler, methods=["POST"]),
|
Route("/upload", endpoint=upload_handler, methods=["POST"]),
|
||||||
Route("/subscribe/{user_id}", endpoint=sse_subscribe_handler),
|
Route("/subscribe/{user_id}", endpoint=sse_subscribe_handler),
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,7 +3,7 @@ aioredis~=2.0.1
|
||||||
alembic==1.11.3
|
alembic==1.11.3
|
||||||
ariadne>=0.17.0
|
ariadne>=0.17.0
|
||||||
asyncio~=3.4.3
|
asyncio~=3.4.3
|
||||||
authlib>=1.1.0
|
authlib==1.2.1
|
||||||
bcrypt>=4.0.0
|
bcrypt>=4.0.0
|
||||||
beautifulsoup4~=4.11.1
|
beautifulsoup4~=4.11.1
|
||||||
boto3~=1.28.2
|
boto3~=1.28.2
|
||||||
|
|
|
@ -5,7 +5,6 @@ from datetime import datetime, timezone
|
||||||
from urllib.parse import quote_plus
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
from graphql.type import GraphQLResolveInfo
|
from graphql.type import GraphQLResolveInfo
|
||||||
from starlette.responses import RedirectResponse
|
|
||||||
from transliterate import translit
|
from transliterate import translit
|
||||||
|
|
||||||
from auth.authenticate import login_required
|
from auth.authenticate import login_required
|
||||||
|
@ -14,17 +13,11 @@ from auth.email import send_auth_email
|
||||||
from auth.identity import Identity, Password
|
from auth.identity import Identity, Password
|
||||||
from auth.jwtcodec import JWTCodec
|
from auth.jwtcodec import JWTCodec
|
||||||
from auth.tokenstorage import TokenStorage
|
from auth.tokenstorage import TokenStorage
|
||||||
from base.exceptions import (
|
from base.exceptions import InvalidPassword, InvalidToken, ObjectNotExist, Unauthorized
|
||||||
BaseHttpException,
|
|
||||||
InvalidPassword,
|
|
||||||
InvalidToken,
|
|
||||||
ObjectNotExist,
|
|
||||||
Unauthorized,
|
|
||||||
)
|
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from base.resolvers import mutation, query
|
from base.resolvers import mutation, query
|
||||||
from orm import Role, User
|
from orm import Role, User
|
||||||
from settings import FRONTEND_URL, SESSION_TOKEN_HEADER
|
from settings import SESSION_TOKEN_HEADER
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("getSession")
|
@mutation.field("getSession")
|
||||||
|
@ -64,19 +57,6 @@ async def confirm_email(_, info, token):
|
||||||
return {"error": "email is not confirmed"}
|
return {"error": "email is not confirmed"}
|
||||||
|
|
||||||
|
|
||||||
async def confirm_email_handler(request):
|
|
||||||
token = request.path_params["token"] # one time
|
|
||||||
request.session["token"] = token
|
|
||||||
res = await confirm_email(None, {}, token)
|
|
||||||
print("[resolvers.auth] confirm_email request: %r" % request)
|
|
||||||
if "error" in res:
|
|
||||||
raise BaseHttpException(res["error"])
|
|
||||||
else:
|
|
||||||
response = RedirectResponse(url=FRONTEND_URL)
|
|
||||||
response.set_cookie("token", res["token"]) # session token
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def create_user(user_dict):
|
def create_user(user_dict):
|
||||||
user = User(**user_dict)
|
user = User(**user_dict)
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
|
|
@ -23,7 +23,7 @@ for provider in OAUTH_PROVIDERS:
|
||||||
"id": environ.get(provider + "_OAUTH_ID"),
|
"id": environ.get(provider + "_OAUTH_ID"),
|
||||||
"key": environ.get(provider + "_OAUTH_KEY"),
|
"key": environ.get(provider + "_OAUTH_KEY"),
|
||||||
}
|
}
|
||||||
FRONTEND_URL = environ.get("FRONTEND_URL") or "http://localhost:3000"
|
FRONTEND_URL = environ.get("FRONTEND_URL") or "https://localhost:3000"
|
||||||
SHOUTS_REPO = "content"
|
SHOUTS_REPO = "content"
|
||||||
SESSION_TOKEN_HEADER = "Authorization"
|
SESSION_TOKEN_HEADER = "Authorization"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user