def wrapper(*args, **kwargs): try: jwt_required(lambda: None)() except UserLoadError: raise InternalServerError('unable to load user') except UserClaimsVerificationError: raise Unauthorized('invalid or expired user info') except JWTExtendedException as ex: raise Unauthorized('authorization error: ' + str(ex)) identity = get_jwt_identity() if identity['type'] == User.Normal: # fail if the user is still suspended if current_user.suspended(): raise Unauthorized('user is suspended') if identity['type'] == User.Student: # make sure the read access is synced up current_user.check_read_access() # verify that the user has the correct permissions for this view if permissions and len( set(permissions).intersection( current_user.permissions_list)) == 0: raise Unauthorized() return fn(*args, **kwargs)
class ProfileApi(BaseResource): """ :URL: ``/api/auth/profile/`` """ endpoints = ['/profile/'] method_decorators = {'get': [jwt_required()], 'put': [jwt_required()]} def get(self): """ * Authorization header containing access token is required :status_code: 200 :response: .. code-block:: python { "user": UserObject } """ return {"user": current_user.dict()} def put(self): """ * Authorization header containing refresh token is required :status_code: 200 :response: .. code-block:: python { "message": "Profile successfully updated" "user": UserObject } """ data = request.get_json() fields = { "first_name": data.get('first_name'), "last_name": data.get('last_name'), "email": data.get('email'), "password": data.get('password'), } for field in fields: if data.get(field): setattr(current_user, field, data[field]) db.session.commit() return { "message": "Profile successfully updated", 'user': current_user.dict() }
def init_app(app): for version in routes.ROUTES: SWAGGER_URL = f'/{version}/api/docs' API_URL = f'/static/{version}/swagger.json' blueprint = Blueprint(version, __name__) module = 'project.server.controllers.%s.' % version swaggerui_blueprint = get_swaggerui_blueprint( SWAGGER_URL, API_URL, config={'app_name': "Sql Module"}, ) for route in routes.ROUTES[version]: endpoint = route.get('endpoint') function = route.get('function') method = route.get('method') rule = route.get('rule') opts = route.get('opts', {}) auth_required = opts.get('auth_required', False) __import__(module + endpoint, fromlist=['']) view_function = restful.restful(**opts)(getattr( sys.modules[module + endpoint], function)) if auth_required: view_function = jwt_required( restful.restful(**opts)(getattr( sys.modules[module + endpoint], function))) blueprint.add_url_rule(rule, endpoint=endpoint + ' ' + function, view_func=view_function, methods=[method], strict_slashes=False) app.register_blueprint(blueprint, url_prefix='/' + version) app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)
def protection_decorator(fn): @wraps(fn) def decorator(*args, **kwargs): # decode JWT-token identity = get_jwt_identity() claims = get_jwt_claims() # check that identity has access to endpoint g.type = claims["type"] log.debug(f"Endpoint accessed as {g.type}") if g.type not in types: log.warning( f"Illegal attempt from {g.type} to access endpoint") raise Exception(f"{g.type}'s are not allowed!") # do some specific stuff per identity g.user = g.container = g.node = None if g.type == 'user': user = get_and_update_authenticatable_info(identity) g.user = user assert g.user.type == g.type elif g.type == 'node': node = get_and_update_authenticatable_info(identity) g.node = node assert g.node.type == g.type elif g.type == 'container': g.container = identity else: raise Exception(f"Unknown entity: {g.type}") return fn(*args, **kwargs) return jwt_required(decorator)
def doc_login_required( func: Callable[..., Callable[..., Any]]) -> Callable[..., Any]: """ 登录限制装饰器 为API添加登录限制,同时添加OpenAPI注释,使用装饰器后 只有带有合法jwt token的请求才能访问。 用法: >>> class SampleView(MethodView): @doc_login_required def get(self): return {'code': 0} """ # pylint: disable=W0212 # 获取登录函数 auth_required_func = jwt_required(func) # 封装函数 @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: return auth_required_func(*args, **kwargs) # 增加验证 wrapper = __set_apidoc(wrapper, func) # type: ignore return wrapper
def doc_login_required(func: Callable) -> Callable: """ 登录限制装饰器 为API添加登录限制,同时添加OpenAPI注释,使用装饰器后 只有带有合法jwt token的请求才能访问。 用法: >>> class SampleView(MethodView): @doc_login_required def get(self): return {'code': 0} """ # pylint: disable=W0212 # 获取登录函数 auth_required_func = jwt_required(func) # 封装函数 @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: return auth_required_func(*args, **kwargs) # 增加验证 wrapper._apidoc = getattr(func, "_apidoc", {}) wrapper._apidoc.setdefault("security", [{"api_key": []}]) return wrapper
def jwt_logged_user(fct, is_anonymous=False): def decoredFuntion(*p, **pn): if fjwt.get_current_user().isAnonymous() != is_anonymous: raise NotFoundError return fct(*p, **pn) return fjwt.jwt_required(decoredFuntion)
class Users(Resource): def __init__(self): self.parser = reqparse.RequestParser() self.parser.add_argument('id', required=True, type=int, help="id can't be blank and it be a number") self.parser.add_argument( 'limit', required=True, type=int, help="limit can't be blank and it be a number") self.parser.add_argument( 'timeout', required=True, type=int, help="timeout can't be blank and it be a number") decorators = [jwt_required()] def get(self): args = self.parser.parse_args() get_f = GetFriends(timeout=float(args['timeout'])) result = get_f.parse_friends(id_user=args['id'], limit=int(args['limit'])) return result
def protection_decorator(fn): @wraps(fn) def decorator(*args, **kwargs): # decode JWT-token identity = get_jwt_identity() claims = get_jwt_claims() roles = set(claims['roles']) type_set = set(types) intersection = type_set.intersection(roles) # log.debug(f'roles: {roles}') # log.debug(f'type_set: {type_set}') # log.debug(f'intersection: {intersection}') # log.debug(f'len(intersection): {len(intersection)}') # Root may do everything :-) is_root_or_for_everyone = ('root' in roles) or ('everyone' in types) if len(intersection) == 0 and not is_root_or_for_everyone: abort(403) return fn(*args, **kwargs) return jwt_required(decorator)
def graphql_view(): """ Create a GraphQL interface with GraphiQL and protected through an access token. """ view = GraphQLView.as_view("", schema=schema, graphiql=False) return jwt_required(view)
def decorator(f): if Envs.DEBUG: @wraps(f) def wrapper(*args, **kwargs): return f(*args, **kwargs) else: wrapper = flask_jwt_extended.jwt_required( *jwt_args, **jwt_kwargs)(f) return wrapper
def decor(*args, **kwargs): try: return jwt_required(func)(*args, **kwargs) except NoAuthorizationError: raise NotAuthorizedError except ExpiredSignatureError: raise TokenGoneOffError except InvalidTokenError: raise M4MInvalidTokenError
class UserList(Resource): """Creation and get_all --- get: tags: - api responses: 200: content: application/json: schema: allOf: - $ref: '#/components/schemas/PaginatedResult' - type: object properties: results: type: array items: $ref: '#/components/schemas/UserSchema' post: tags: - api requestBody: content: application/json: schema: UserSchema responses: 201: content: application/json: schema: type: object properties: msg: type: string example: user created user: UserSchema """ method_decorators = [jwt_required()] def get(self): schema = UserSchema(many=True) query = User.query return paginate(query, schema) def post(self): schema = UserSchema() user = schema.load(request.json) db.session.add(user) db.session.commit() return {"msg": "user created", "user": schema.dump(user)}, 201
def graphql(): view = GraphQLView.as_view('graphql', schema=auth_required_schema, graphiql=True, get_context=lambda: { 'session': session, 'request': request, 'uid': get_jwt_identity() }) return jwt_required(view)
def authenticate(func: Callable) -> Callable: """ Decorator to add jwt view authentication. Reference: https://github.com/tiangolo/full-stack-flask-couchdb/tree/master/%7B%7Bcookiecutter.project_slug%7D%7D/backend/app/app/api/api_v1. """ func = api_doc( security=current_app.config.get("APISPEC_SECURITY_PARAMS", []))( jwt_required(func)) return func
class ResetPassword(MethodView): decorators = [jwt_required()] @validate_input(PasswordSchema) def patch(self, data: PasswordSchema): user_services.reset_password(get_jwt_identity(), data.password) return {}, 204
def user_required(f): def __inner__(self, *args, **kwargs): identify = get_jwt_identity() user = models.User.find_by_username(identify) if user and user.role in ['admin', 'user']: return f(self, user, *args, **kwargs) return { 'message': 'Not found', }, 404 return jwt_required(__inner__)
def wrapped(*args, **qwargs): try: return jwt_required(fn)(*args, **qwargs) except NoAuthorizationError: pass api_key = request.values.get('apiKey', '') if api_key != (settings.DEFAULT_API_KEY or API_KEI_TOKEN): raise AuthenticationError("Invalid api token") return fn(*args, ** qwargs)
class ChangePassword(MethodView): decorators = [jwt_required()] @validate_input(NewPasswordSchema) def patch(self, data: NewPasswordSchema): if user_services.change_password(get_jwt_identity(), password=data.password, new_password=data.new_passowrd): return {}, 204 return {'error': 'invalid password'}, 400
def wrapper(*args, **kwargs): nonlocal f # called in reverse order, self_only after auth steps if self_only: f = __self_only(f) f = __load_user_to_g(f) if auth_method is AuthType.JWT: f = jwt_required(f) elif auth_method is AuthType.Simple: f = httpauth.login_required(f) return f(*args, **kwargs)
class UserCurrent(MethodView): decorators = [jwt_required()] def get(self): user = user_services.get_by_id(get_jwt_identity()) output_schema = filters.get_schema(query_string=request.args, schema_cls=UserOutputSchema) output_fields = filters.get_fields(request.args) response = output_schema.from_orm(user).dict(include=output_fields) return response, 200
class TokenRefresh(MethodView): decorators = [jwt.jwt_required(refresh=True)] def get(self): user_id = jwt.get_jwt_identity() user, token, refresh_token = auth_services.token_refresh(user_id) return { 'user': UserOutputSchema.from_orm(user).dict(), 'token': token, 'refresh_token': refresh_token }, 200
def admin_required(view_function): @wraps(view_function) def wrapper(*args, **kwargs): current_user = get_current_user() if current_user.role == 'admin': authorized = True else: authorized = False if not authorized: raise PermissionDeniedException("Insufficient Privilege") return view_function(*args, **kwargs) return jwt_required(wrapper)
def decoratoruserrole(apifunction): @wraps(apifunction) def wrapper(*args, **kwargs): jwt_data = _decode_jwt_from_request(request_type='access') if ACCESS[jwt_data["identity"][1]] >= ACCESS[urole]: isRoleAuthorized = True else: isRoleAuthorized = False if not isRoleAuthorized: raise NoAuthorizationError( "You are not authorized user to access the API") return apifunction(*args, **kwargs) return jwt_required(wrapper)
class MediaStorage(MethodView): decorators = [jwt_required()] allowed_formats = ['jpg', 'png', 'mp4'] def get(self): media_format = request.args.get('media_format') if not media_format or media_format not in self.allowed_formats: return {'media_format': ['Must be one of: jpg, mp4, png']}, 401 file_key = f'{uuid.uuid4().hex}.{media_format}' url = storage.put_url(file_key=file_key) return {'media_url': url, 'media_name': file_key}, 200
def configure_graphql(app: Flask): from yaits_api.services.users import get_user_by_id class FlaskAuthorizationMiddleware(object): def resolve(self, next, root, info, **kwargs): identity = get_jwt_identity() user = get_user_by_id(identity['unique_id']) info.context.yaits_user = user return next(root, info, **kwargs) graphql_view = jwt_required( GraphQLView.as_view( 'graphql', schema=schema, graphiql=True, middleware=[FlaskAuthorizationMiddleware()], )) app.add_url_rule('/graphql', view_func=graphql_view, methods=['POST', 'GET'])
def api_auth_required(f): auth_decorated = jwt_required(f) @wraps(f) def decorated(): if request.method == "OPTIONS": return f() session_user = current_user._get_current_object() if isinstance(session_user, FreeUser): logging.debug(f"Authentication bypassed`") return f() if session_user.is_authenticated: logging.debug( f"@{session_user.username} authenticated via `session`") return f() logging.debug("JWT authentication pending") return auth_decorated() return decorated
class RefreshTokenApi(BaseResource): """ :URL: ``/api/auth/refresh-token/`` """ endpoints = ['/refresh-token/'] method_decorators = [jwt_required(refresh=True)] def post(self): """ * Authorization header containing refresh token is required :status_code: 200 :response: .. code-block:: json { "access_token": "access_token" } """ current_user = get_jwt_identity() access_token = create_access_token(identity=current_user) return {'access_token': access_token}
def create_app(configname='default_config', app_name=None, modules=None): print 'start server' app = Flask(__name__, static_folder='./static', template_folder='templates') print 'config name: ', configname app.config.from_pyfile(os.path.join('config', configname + '.py')) global server_app server_app = app configure_logging(app) configure_extensions(app) if not app.config['PRODUCTION']: authentication.register_authenticator(DummyAuthenticator()) authentication.register_authenticator(GMIAuthenticator()) authentication.register_authenticator(BoxAuthenticator()) app.register_blueprint(api) app.register_blueprint(auth) graphql_sec_view = jwt_required( CustomGraphQLView.as_view('graphql', schema=schema, graphiql=False)) app.add_url_rule('/graphql', view_func=graphql_sec_view) if not app.config['PRODUCTION']: graphql_view = CustomGraphQLView.as_view('graphql_insec', schema=schema, graphiql=True) app.add_url_rule('/graphql_insec', view_func=graphql_view) server_app = app signal.signal(signal.SIGINT, exit_handler) app.logger.info('Server Created') @app.teardown_appcontext def shutdown_session(exception=None): db.session.remove() return app
def _make_resource(func, api, method, requires_authentication=False): location = 'form' if method in ['put', 'post'] else 'args' compat = True if (func._methods is not None) else False parser = make_parser(func._spec, location=location, compat=compat) @api.expect(parser, validate=True, strict=True) def _method(self): req = parser.parse_args() output = func(**req) return jsonify(output) error_docs = func._spec['error_docs'] security = 'bearer_token' if requires_authentication else None _method = api.doc(responses=error_docs, security=security)(_method) if requires_authentication: _method = jwt_required()(_method) _method.__doc__ = func._spec['docstring'] Tranquilized = type('Tranquilized', (Resource, ), {method: _method}) return Tranquilized