Commit be7e367a authored by crazywoola's avatar crazywoola

feat: add passport services

parent 1f9fa549
......@@ -7,4 +7,4 @@ bp = Blueprint('web', __name__, url_prefix='/api')
api = ExternalApi(bp)
from . import completion, app, conversation, message, site, saved_message, audio
from . import completion, app, conversation, message, site, saved_message, audio, passport
# -*- coding:utf-8 -*-
import uuid
from controllers.web import api
from flask_restful import Resource
from flask import current_app, request
from werkzeug.exceptions import Unauthorized, NotFound
from models.model import Site, EndUser, App
from extensions.ext_database import db
from libs.passport import PassportService
class PassportResource(Resource):
"""Base resource for passport."""
def get(self):
app_id = request.headers.get('X-Site-Code')
if app_id is None:
raise Unauthorized('X-Site-Code header is missing.')
sk = current_app.config.get('SECRET_KEY')
# get site from db and check if it is normal
site = db.session.query(Site).filter(
Site.code == app_id,
Site.status == 'normal'
).first()
if not site:
raise NotFound()
# get app from db and check if it is normal and enable_site
app_model = db.session.query(App).filter(App.id == site.app_id).first()
if not app_model or app_model.status != 'normal' or not app_model.enable_site:
raise NotFound()
end_user = EndUser(
tenant_id=app_model.tenant_id,
app_id=app_model.id,
type='browser',
is_anonymous=True,
session_id=generate_session_id(),
)
db.session.add(end_user)
db.session.commit()
payload = {
"iss": site.app_id,
'sub': 'Web API Passport',
"aud": end_user.id,
'app_id': site.app_id,
'end_user_id': end_user.id,
}
tk = PassportService(sk, payload).get_token()
return {
'access_token': tk,
}
api.add_resource(PassportResource, '/passport')
def generate_session_id():
"""
Generate a unique session ID.
"""
while True:
session_id = str(uuid.uuid4())
existing_count = db.session.query(EndUser) \
.filter(EndUser.session_id == session_id).count()
if existing_count == 0:
return session_id
......@@ -9,6 +9,26 @@ from werkzeug.exceptions import NotFound, Unauthorized
from extensions.ext_database import db
from models.model import App, Site, EndUser
def validate_jwt_token(view=None):
def decorator(view):
@wraps(view)
def decorated(*args, **kwargs):
site = get_site_from_jwt_token()
app_model = db.session.query(App).filter(App.id == site.app_id).first()
if not app_model:
raise NotFound()
if app_model.status != 'normal':
raise NotFound()
if not app_model.enable_site:
raise NotFound()
end_user = get_end_user_from_jwt_token()
return view(app_model, end_user, *args, **kwargs)
return decorated
def validate_token(view=None):
def decorator(view):
......@@ -47,9 +67,9 @@ def validate_and_get_site():
if ' ' not in auth_header:
raise Unauthorized('Invalid Authorization header format. Expected \'Bearer <api-key>\' format.')
auth_scheme, auth_token = auth_header.split(None, 1)
auth_scheme, auth_tokens = auth_header.split(None, 1)
auth_scheme = auth_scheme.lower()
auth_token, jwt_token = [token.strip() for token in auth_tokens.split(',')]
if auth_scheme != 'bearer':
raise Unauthorized('Invalid Authorization header format. Expected \'Bearer <api-key>\' format.')
......@@ -104,5 +124,11 @@ def generate_session_id():
return session_id
def get_site_from_jwt_token():
return "site"
def get_end_user_from_jwt_token():
return "end_user"
class WebApiResource(Resource):
method_decorators = [validate_token]
# -*- coding:utf-8 -*-
import jwt
class PassportService:
def __init__(self, sk, payload):
self.sk = sk
self.payload = payload
def get_token(self):
return jwt.encode(self.payload, self.sk, algorithm='HS256')
def verify_token(self, token):
return jwt.decode(token, self.sk, algorithms=['HS256'])
......@@ -33,4 +33,4 @@ openpyxl==3.1.2
chardet~=5.1.0
docx2txt==0.8
pypdfium2==4.16.0
flask-jwt-extended==4.5.2
\ No newline at end of file
pyjwt~=2.6.0
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment