How to pass variable from middleware to resource in falcon? - python

I'm using Falcon, I need pass variable from middleware to resource, how can I do that?
main.py
app = falcon.API(middleware=[
AuthMiddleware()
])
app.add_route('/', Resource())
and auth
class AuthMiddleware(object):
def process_request(self, req, resp):
self.vvv = True
and resource
class Resource(object):
def __init__(self):
self.vvv = False
def on_get(self, req, resp):
logging.info(self.vvv) #vvv is always False
why self.vvv is always false? I have changed it in middleware to true.

First of all you are confussing what self means. Self affects only to the instance of the class, is a way of adding attributes to your class, therefore your self.vvv in AuthMiddleware is a complete different attribute from your self.vvv in your class Resource.
Second, you do not need to know anything from AuthMiddleware in your resource, thats why you want to use middleware. Middleware is a way to execute logic after or before each request. You need to implement your middleware so it raises Falcon exceptions or either modifies your request or response.
For example, if you don't authorize a request, you must raise an exception like this:
class AuthMiddleware(object):
def process_request(self, req, resp):
token = req.get_header('Authorization')
challenges = ['Token type="Fernet"']
if token is None:
description = ('Please provide an auth token '
'as part of the request.')
raise falcon.HTTPUnauthorized('Auth token required',
description,
challenges,
href='http://docs.example.com/auth')
if not self._token_is_valid(token):
description = ('The provided auth token is not valid. '
'Please request a new token and try again.')
raise falcon.HTTPUnauthorized('Authentication required',
description,
challenges,
href='http://docs.example.com/auth')
def _token_is_valid(self, token):
return True # Suuuuuure it's valid...
Check Falcon page examples.

From https://falcon.readthedocs.io/en/stable/api/middleware.html:
In order to pass data from a middleware function to a resource function use the req.context and resp.context objects. These context objects are intended to hold request and response data specific to your app as it passes through the framework.
class AuthMiddleware(object):
def process_request(self, req, resp):
# self.vvv = True # -
req.context.vvv = True # +
class Resource(object):
# def __init__(self): # -
# self.vvv = False # -
def on_get(self, req, resp):
# logging.info(self.vvv) # -
logging.info(req.context.vvv) # +
You should not use the attributes on middleware and resource instances for your request data. Since you only instantiate them once, modifying their attributes is generally not thread-safe.

Related

How to access the request in models.py, django

#property
def get_maca(self, request):
if request.user.name == "example":
return self
I want to do something like this. If the user name is example return that object.
How to access the request like this?
The standard way is to pass the request, or in your case just the user object, from the view/router all the way down to the models.
This gets very quickly out of hand in a larger project, so my approach is to use thread local to save some of the request context that I like to have available across the whole project. The thread local storage will keep data available inside a single thread, without it being accessible from other threads - great if you're gonna run the Django app on a production server.
Start with the local storage:
from threading import local
_active_user = local()
def activate_user(user):
if not user:
return
_active_user.value = user
def deactivate_user():
if hasattr(_active_user, "value"):
del _active_user.value
def get_user():
"""Returns `(is_anonymous, user)` ."""
active_user = getattr(_active_user, "value", None)
if active_user and active_user is not AnonymousUser:
try:
return False, active_user
except AttributeError:
pass
return True, None
Now that's all good, you can use this manually. Calling activate_user will make you be able to call get_user in any place in your project. However, this is error prone - if you forget to call deactivate_user, the user object will still be available to the next coming request.
The rest of the answer is to show how to make things automatic.
Let's first make a middleware to clean up by calling deactivate_user after every single request.
class ThreadCleanupMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Executed for each request/response after
# the view is called.
deactivate_user()
return response
Add a path to the ThreadCleanupMiddleware to the end of your settings.MIDDLEWARE list.
Finish up with a view mixin that activates the user automatically (that's for class based views; if you're using functional views, it would be a decorator instead):
class ContextViewSetMixin:
def initial(self, request, *args, **kwargs):
super().initial(request, *args, **kwargs)
if request.user.is_authenticated:
activate_user(request.user)
class ContextModelViewSet(ContextViewSetMixin, viewsets.ModelViewSet):
pass

How to mock an mutation argument in Django?

I have a mutation that has a decorator that checks the permissions (scopes) from the user token before s/he goes inside it. The decorator gets the input parameter from the mutate method and extracts the token and verify if the user has one of the allowed scopes.
The unit tests don't succeed if I don't remove or mock the requires_scope part from the code. The problem is that I don't know exactly what I have to mock to succeed in the unit tests. Should I mock the input itself? The token? The return of the requires_scopes decorator?
mutations.py
class MyMutation(graphene.Mutation):
success = graphene.Boolean()
class Arguments:
input = graphene.Argument(IdInput, required=True)
#classmethod
#requires_scopes(['app:first_test_permission', 'app:second_test_permission'])
def mutate(cls, root, info, input):
pass
decorators.py
def get_access_token_from_header(request):
"""
Obtains the Access Token from the Authorization Header
"""
header = request.context.META.get('HTTP_AUTHORIZATION', None)
header = header.split()
token = header[1]
return token
def requires_scopes(scopes: list):
"""
Determines if the required scope is present in the Access Token
Args:
scopes (list): The scopes required to access the resource
"""
def require_scopes(f):
#wraps(f)
def decorated(*args, **kwargs):
token = get_access_token_from_header(args[2])
decoded = jwt.decode(token, verify=False)
if decoded.get("scope"):
token_scopes = set(decoded["scope"].split())
required_scopes = set(scopes)
if required_scopes.intersection(token_scopes):
return f(*args, **kwargs)
raise Exception({'message': 'You don\'t have access to this resource'})
return decorated
return require_scopes
I mocked the get_access_token_from_header function:
MY_TOKEN = 'mytoken'
#patch('app.decorators.get_access_token_from_header', return_value=MY_TOKEN)
def test_my_mutation_successfully(self, get_access_token_from_header_mocker):
pass

How can we get path params in falcon middleware, if any path param in the route?

My routes are as follows:
app.add_route('/v1/my_route', MyResource())
app.add_route('/v1/my_route/{app_id}', MyResource())
app.add_route('/v1/my_route2/any_route', AnyRouteResource())
app.add_route('/v1/my_route2/any_route/{app_id}', AnyRouteResource())
and Middleware is something similar to
class MyMiddleware(object):
def process_request(self, req, resp):
/** Here i want to get <app_id> value if it is passed **/
You can get every attribute of the request object from req. For example, to get the path of your resource:
class MyMiddleware(object):
def process_request(self, req, resp):
path = req.path
# process your path here
Check the docummentation for more info about requests.
If you want to get the app_id directly, just extend the method with params, falcon will do the job.
class MyMiddleware(object):
def process_request(self, req, resp, params):
app_id = params["app_id"]
There is process_resource(self, req, resp, resource, params) method in the base middleware. You can override it. There params is a dict like object with params extracted from the uri template fields.
https://falcon.readthedocs.io/en/stable/api/middleware.html

How do I get the Resource object from URI in django-tastypie?

Say I have some ModelResource classes and they are registered with a tastypie API endpoint (say api/v1/posts, api/v1/authors).
Given a URI (such a api/v1/posts), I need to get an instance of PostResource so as to execute PostResource.get_list()
class PostResource(ModelResource):
def get_list(self, *args, **kwargs):
...
class AuthorResource(ModelResource):
def get_list(self, *args, **kwargs):
...
Question is - Given the url api/v1/posts, what is the pythonic/django/tastypie way to get an instance of PostResource?
I can anyways maintain a reverse mapping in my code and that would work, but there would definitely be a better solution.
Look at get_via_uri function.
You probably need this part:
from django.core.urlresolvers import resolve, get_script_prefix, Resolver404
from tastypie.exceptions import NotFound
prefix = get_script_prefix()
chomped_uri = uri
if prefix and chomped_uri.startswith(prefix):
chomped_uri = chomped_uri[len(prefix)-1:]
try:
resource, args, kwargs = resolve(chomped_uri)
except Resolver404:
raise NotFound("The URL provided '%s' was not a link to a valid resource." % uri)
Where uri is Your URI. resource is Your Resource instance.

Google App Engine, define a Preprocessing class

I am trying to define a base request handling class so that the webapp pages may inherit some basic methods and variable which otherwise would be required to be repeatedly be defined for each page of the application. A sort of similar functionality like django preprocessors. This is my base class from which other pages inherit:
class BasePage(webapp.RequestHandler):
def __init__(self):
self.user = users.get_current_user()
self.template_values = {
'user': self.user,
'environ': self, #I don't like the idea of passing the whole environ object to a template
##The below three functions cannot be executed during _init_ because of absence of self.request
#'openid_providers': self.openid_providers(),
#'logout_url': self.get_logout_url(),
#'request': self.get_request(),
}
##A sort of similar functionality like render_to_response in django
def render_template(self, template_name, values = None, *args, **kwargs):
#PATH is the directory containing the templates
if values:
for value in values: self.template_values[value] = values[value]
self.response.out.write(template.render(PATH+template_name, self.template_values, *args, **kwargs))
##Returns request as the name suggests
def logout_url(self):
return users.create_logout_url(self.request.url)
##Returns request as the name suggests
def request(self):
return request
##Returns openid login urls
def openid_providers(self):
#OPENID_POVIDERS is a list of dictionary
for p in OPENID_PROVIDERS:
p['login_url'] = users.create_login_url(self.request.get('next', '/') , p['name'], p['url'])
return OPENID_PROVIDERS
Everything is working fine except that I cannot pass some variables during initialization as self.request is not available. So for a workaround what I did is pass on whole self variable as a template variable.
Is there some other way to provide the template variables (request, logout_url etc) to the templates?
A much simpler solution than bgporter's is to do the common setup in the initialize method of webapp.RequestHandler. Here's an example from work, where we wanted to add a Django-like is_ajax method to the request object:
class BaseHandler(webapp.RequestHandler):
def initialize(self, request, response):
super(BaseHandler, self).initialize(request, response)
# Add a Django-like is_ajax() method to the request object
request.is_ajax = lambda: \
request.environ.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
This method is called to, uh, initialize each request handler with the current request and response objects, before the appropriate get or post (or whatever) methods are called.
I've solved that problem in my AppEngine code by using the Template Method Pattern
Basically, the base class looks like:
class MyBasePage(webapp.RequestHandler):
def __init__(self):
# common setup/init stuff here,
# omitted for this discussion
def Setup(self):
# request handling setup code needed in both GET/POST methods, like
# checking for user login, getting session cookies, etc.
# omitted for this discussion
def get(self, *args):
self.Setup()
# call the derived class' 'DoGet' method that actually has
# the logic inside it
self.DoGet(*args)
def post(self, *args):
self.Setup()
# call the derived class' 'DoPost' method
self.DoPost(*args)
def DoGet(self, *args):
''' derived classes override this method and
put all of their GET logic inside. Base class does nothing.'''
pass
def DoPost(self, *args):
''' derived classes override this method and
put all of their POST logic inside. Base class does nothing.'''
pass
...your derived classes then mostly just need to worry about the guts of those DoGet() and DoPost() methods.

Categories