I am currently developing an flask api that uses flask-jwt-extended to protect endpoints. I have the jwt required decorator working correctly but I would like to add roles to have more granular control over access. In my imagination it would be best to have three tables Users, Roles and UserRoles. UserRoles would map users to roles using foreign ids and then use a custom decorator to check for each endpoint.
I have never done this before, how would you implement this and why?
As you suggested, having some basic tables and methods + decorators is the way to go.
You can also look into how this is implemented in Flask-Security
(or in packages Flask-Login and Flask-Principal, which are used in Flask-Security). It can give you some suggestions on what kind of functions you'd like to have.
According to the docs, it should be possible with custom decorators, like this:
from flask_jwt_extended import get_jwt
from flask_jwt_extended import verify_jwt_in_request
# Here is a custom decorator that verifies the JWT is present in the request,
# as well as insuring that the JWT has a claim indicating that this user is
# an administrator
def admin_required():
def wrapper(fn):
#wraps(fn)
def decorator(*args, **kwargs):
verify_jwt_in_request()
claims = get_jwt()
if claims["is_administrator"]:
return fn(*args, **kwargs)
else:
return jsonify(msg="Admins only!"), 403
return decorator
return wrapper
Just make sure that you save roles information using additional claims.
Related
I'm trying to build a jumptable of API methods for a variety of boto3 clients, so I can pass an AWS service name and a authn/authz low-level boto3 client to my utility code and execute the appropriate method to get a list of resources from the AWS service.
I'm not willing to hand-code and maintain a massive if..elif..else statement with >100 clauses.
I have a dictionary of service names (keys) and API method names (values), like this:
jumpTable = { 'lambda' : 'list_functions' }
I'm passed the service name ('lambda') and a boto3 client object ('client') already connected to the right service in the region and account I need.
I use the dict's get() to find the method name for the service, and then use a standard getattr() on the boto3 client object to get a method reference for the desired API call (which of course vary from service to service):
`apimethod = jumpTable.get(service)`
`methodptr = getattr(client, apimethod)`
Sanity-checking says I've got a "botocore.client.Lambda object" for 'client' (that looks OK to me) and a "bound method ClientCreator._create_api_method.._api_call of <botocore.client.Lambda" for the methodptr which reports itself as of type 'method'.
None of the API methods I'm using require arguments. When I invoke it directly:
'response = methodptr()'
it returns a boto3 ClientError, while invoking at through the client:
response = client.methodptr()
returns a boto3 AttributeErrror.
Where am I going wrong here?
I'm locked into boto3, Python3, AWS and have to talk to 100s of AWS services, each of which has a different API method that provides the data I need to gather. To an old C coder, a jump-table seems obvious; a more Pythonic approach would be welcome...
The following works for me:
client = boto3.Session().client("lambda")
methodptr = getattr(client, apimethod)
methodptr()
Note that the boto3.Session() part is required. When calling boto3.client(..) directly, I get a 'UnrecognizedClientException' exception.
I am exploring ways to automate REST API resource and endpoint implementation using flask-restful. In flask-restful, the add_resource(UpdateOrders, '/orders') function links the endpoint to the resource in the framework. UpdateOrders is the endpoint, and also the name of a class containing logic for handling requests sent to '/orders'.
I could manually specify the endpoints and resources like this:
app = Flask(__name__)
api = Api(app)
# only Orders endpoint included for simplicity
class Orders(Resource):
def get(self, item_id):
return order_data[item_id]
def add_resources():
api.add_resource(UpdateOrders, '/orders')
api.add_resource(Orders, '/orders/<item_id>')
api.add_resource(UpdatePayments, '/payments')
api.add_resource(Payments, '/payments/<item_id>')
if __name__ == '__main__':
add_resources()
app.run()
However, both the endpoints and resources will change depending on the use case of the REST API, e.g. instead of '/orders' I could have '/appointments'. I don't know what the use case will be (it is generated from the user's business process choreography).
My initial thought was to start by adding resources dynamically:
def add_resources():
# generate list of endpoint, resource tuples
endpoint_resource = [('UpdateOrders', '/orders'),
('Orders', '/orders/<item_id>'),
('UpdatePayments', '/payments'),
('Payments', '/payments/<item_id>')]
for endpoint, resource in endpoint_resource:
api.add_resource(endpoint, resource)
Of course, this won't work as endpoint here is a string, while add_resource requires a class. So my question is: can/should I convert endpoint from a string to a variable class name so that the API's resources can be created 'dynamically'?
In other words, instead of endpoint being assigned first to string 'UpdateOrders', it will be assigned to <class '__main__.UpdateOrders'>.
Any guidance is appreciated!
I just started learning NestJS and GraphQL. I started with a single resolver class UserResolver defined in UserModule. This class provides methods to read a list of users or a specific user. Methods are decorated with #Query(), a user.graphqlfile is provided, GraphQL is initialized in AppModule, all as described in the docs. All works well, I can get a list of users or specific user through Insomnia Tool or through Playground. I am happy!
Now I have created a second module, RoleModule. I created a role.graphql file and a RoleResolver class, I basically replicated all the work done for User but this time for Role. The GraphQL type definition for type Role as well as the Query definitions in the role.graphql file are recognized. What is not recognized are my Query() implementations in the RoleResolver class, they are not getting invoked.
If I put all these Role related #Query() definitions into the UserResolver class, these Role related queries are now getting invoked.
Is that expected behavior? Do I need to put all my GraphQL query definitions into a single class? Is it possible to spread NestJS-GraphQL resolver implementations over several modules? Am I doing something wrong? Please help.
Make sure that you import Query from #nestjs/graphql and not from #nestjs/common.
I wanted to use Locust for performance testing on Spring Rest WebService, where each service is secured by the token.
is anyone tried to do the same by nesting task sets?
How can we maintain the same token for all the request from single user?
is it possible to go to the task on response from other task?
I had a similar scenario. If you know what the token is in advance, you can do:
def on_start(self):
""" on_start is called when a Locust starts, before any task is scheduled """
self.access_token = "XYZ" # method 1
# self.login() # <-- method 2
Otherwise you could call something like a login method that would authenticate your user, and then store the resulting token on self.
Since on start happens before any tasks, I never had to worry about nesting task sets.
If you need things to happen in a certain order within tasks, you can just run something like:
#task(1)
def mytasks(self):
self.get_service_1()
self.get_service_2()
I have a simple application using the Play! framework's secure module. My 'Users' controller extends CRUD and is protected by #Check('admin'), so users have to be admins to access CRUD methods. However, I'd like anyone to be able to create new Users-- like a "Sign Up" or "Register" button.
What is a good way to do this, given that all of my Users methods except Create should be protected? Can I apply #Check("admin") to individual methods?
Here is my Users controller:
package controllers;
import play.*;
import play.mvc.*;
#Check("admin")
#With(Secure.class)
public class Users extends CRUD {
};
What is a good way to do this, given that all of my Users methods except Create should be protected?
In my practice, I create new controller in another package with the same name for doing this.
For example,
So, I think the best way is you should put Sign up method in the Non-Admin.
After I find some reference, this link has same idea with you and the answer of this topic is like what I said.
Can I apply #Check("admin") to individual methods?
Yes, you can. But you need to use #With(Secure.class) in that controller first.
You can see the example in Secure Module Documentation.