First Commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
from . import main
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,130 @@
|
||||
import datetime
|
||||
import functools
|
||||
import json
|
||||
import uuid
|
||||
|
||||
import jwt
|
||||
|
||||
from odoo import fields, http
|
||||
from odoo.http import request
|
||||
from odoo.tools import config
|
||||
|
||||
|
||||
JWT_ISSUER = 'odoo'
|
||||
JWT_AUDIENCE = 'odoo-api'
|
||||
|
||||
|
||||
def json_response(payload, status=200):
|
||||
return request.make_response(
|
||||
json.dumps(payload),
|
||||
headers=[('Content-Type', 'application/json')],
|
||||
status=status,
|
||||
)
|
||||
|
||||
|
||||
def get_jwt_secret():
|
||||
secret_key = config.get('jwt_secret')
|
||||
if not secret_key or len(secret_key) < 32:
|
||||
return None
|
||||
return secret_key
|
||||
|
||||
|
||||
def check_jwt_auth(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
auth_header = request.httprequest.headers.get('Authorization', '')
|
||||
|
||||
if not auth_header.startswith('Bearer '):
|
||||
return json_response({'error': 'Bearer token is required.'}, status=401)
|
||||
|
||||
secret_key = get_jwt_secret()
|
||||
if not secret_key:
|
||||
return json_response({'error': 'JWT secret is not configured.'}, status=500)
|
||||
|
||||
token = auth_header.split(' ', 1)[1].strip()
|
||||
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
secret_key,
|
||||
algorithms=['HS256'],
|
||||
issuer=JWT_ISSUER,
|
||||
audience=JWT_AUDIENCE,
|
||||
options={'require': ['exp', 'iat', 'sub', 'client_id']},
|
||||
)
|
||||
user_id = int(payload['sub'])
|
||||
client = request.env['api.client'].sudo().search([
|
||||
('client_id', '=', payload['client_id']),
|
||||
('active', '=', True),
|
||||
('user_id', '=', user_id),
|
||||
], limit=1)
|
||||
user = request.env['res.users'].sudo().browse(user_id).exists()
|
||||
if not client or not user or not user.active:
|
||||
return json_response({'error': 'Token subject is not allowed.'}, status=401)
|
||||
|
||||
request.jwt_payload = payload
|
||||
request.jwt_client = client
|
||||
request.jwt_user_id = user_id
|
||||
request.update_env(user=user_id)
|
||||
except jwt.ExpiredSignatureError:
|
||||
return json_response({'error': 'Token has expired.'}, status=401)
|
||||
except (jwt.InvalidTokenError, ValueError):
|
||||
return json_response({'error': 'Token is invalid.'}, status=401)
|
||||
|
||||
return func(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
class JwtAuthController(http.Controller):
|
||||
|
||||
@http.route('/api/auth/token', type='http', auth='public', methods=['POST'], csrf=False)
|
||||
def generate_token(self, **kwargs):
|
||||
data = request.httprequest.get_json(silent=True) or kwargs
|
||||
client_id = data.get('client_id')
|
||||
client_secret = data.get('client_secret') or data.get('secret_key')
|
||||
|
||||
if not client_id or not client_secret:
|
||||
return json_response({'error': 'client_id and client_secret are required.'}, status=400)
|
||||
|
||||
secret_key = get_jwt_secret()
|
||||
if not secret_key:
|
||||
return json_response({'error': 'JWT secret is not configured.'}, status=500)
|
||||
|
||||
client = request.env['api.client'].sudo().search([
|
||||
('client_id', '=', client_id),
|
||||
('active', '=', True),
|
||||
], limit=1)
|
||||
|
||||
if not client or not client._check_secret(client_secret) or not client.user_id.active:
|
||||
return json_response({'error': 'Invalid credentials.'}, status=401)
|
||||
|
||||
now = datetime.datetime.now(datetime.UTC)
|
||||
expires_at = now + datetime.timedelta(seconds=client.token_ttl)
|
||||
payload = {
|
||||
'iss': JWT_ISSUER,
|
||||
'aud': JWT_AUDIENCE,
|
||||
'exp': expires_at,
|
||||
'iat': now,
|
||||
'jti': str(uuid.uuid4()),
|
||||
'sub': str(client.user_id.id),
|
||||
'client_id': client.client_id,
|
||||
}
|
||||
token = jwt.encode(payload, secret_key, algorithm='HS256')
|
||||
client.last_used = fields.Datetime.now()
|
||||
|
||||
return json_response({
|
||||
'access_token': token,
|
||||
'expires_in': client.token_ttl,
|
||||
'token_type': 'Bearer',
|
||||
})
|
||||
|
||||
@http.route('/api/ifc/projects', type='http', auth='public', methods=['GET', 'POST'], csrf=False)
|
||||
@check_jwt_auth
|
||||
def get_ifc_projects(self, **kwargs):
|
||||
return json_response({
|
||||
'message': 'JWT token is valid.',
|
||||
'user_id': request.env.user.id,
|
||||
'user_name': request.env.user.name,
|
||||
'client_id': request.jwt_payload.get('client_id'),
|
||||
'data': ['Proyek_IFC_Gedung_A', 'Proyek_IFC_Infrastruktur_B'],
|
||||
})
|
||||
Reference in New Issue
Block a user