2013-06-13 2 views
4

Вот два декоратора, которые я хотел бы объединить, поскольку они очень похожи, разница в том, как обрабатывается не аутентифицированный пользователь. Я бы предпочел иметь один декоратор, который я могу вызвать с аргументом.Объедините два декоратора python в один

# Authentication decorator for routes 
# Will redirect to the login page if not authenticated 
def requireAuthentication(fn): 
    def decorator(**kwargs): 
     # Is user logged on? 
     if "user" in request.session: 
      return fn(**kwargs) 
     # No, redirect to login page 
     else: 
      redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else ''))) 
    return decorator 

# Authentication decorator for routes 
# Will return an error message (in JSON) if not authenticated 
def requireAuthenticationJSON(fn): 
    def decorator(**kwargs): 
     # Is user logged on? 
     if "user" in request.session: 
      return fn(**kwargs) 
     # No, return error 
     else: 
      return { 
       "exception": "NotAuthorized", 
       "error" : "You are not authorized, please log on" 
      } 
    return decorator 

И в настоящее время я использую эти декораторы для определенных маршрутов, например,

@get('/day/') 
@helpers.requireAuthentication 
def day(): 
    ... 

@get('/night/') 
@helpers.requireAuthenticationJSON 
def night(): 
    ... 

я гораздо больше предпочитаю это:

@get('/day/') 
@helpers.requireAuthentication() 
def day(): 
    ... 

@get('/night/') 
@helpers.requireAuthentication(json = True) 
def night(): 
    ... 

Я на питона 3.3 с использованием рамок бутылки. Можно ли делать то, что я хочу? Как?

ответ

2

Просто добавьте еще одну оболочку, чтобы захватить json параметр:

def requireAuthentication(json=False): 
    def decorator(fn): 
     def wrapper(**kwargs): 
      # Is user logged on? 
      if "user" in request.session: 
       return fn(**kwargs) 

      # No, return error 
      if json: 
       return { 
        "exception": "NotAuthorized", 
        "error" : "You are not authorized, please log on" 
       } 
      redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else ''))) 
     return wrapper 
    return decorator 

Я переименованную исходную requireAuthentication функцию decorator (потому что это то, что функция сделал, он украшен fn) и переименовал старый decorator в wrapper, обычный соглашение.

Независимо от того, что вы положили после@ - выражение, оцененное первым, чтобы найти фактическую функцию декоратора. @helpers.requireAuthentication() означает, что вы хотите позвонить в requireAuthentication, и это . Возвращаемое значение затем используется как фактический декоратор для функции, к которой относится линия @.

1

Вы можете создать оболочку для обоих этих декораторов:

def requireAuthentication(json=False): 
    if json: 
     return helpers.requireAuthenticationJSON 
    else: 
     return helpers.requireAuthentication 

Или

import functools 
# Authentication decorator for routes 
# Will redirect to the login page if not authenticated 
def requireAuthentication(json=False): 
    def requireAuthentication(fn): 
     @functools.wraps(fn) 
     def decorator(*args, **kwargs): 
      # Is user logged on? 
      if "user" in request.session: 
       return fn(*args, **kwargs) 
      if json: 
       return { 
       "exception": "NotAuthorized", 
       "error" : "You are not authorized, please log on" 
      } 
      return redirect('/login?url={0}{1}'.format(request.path, 
                 ("?" + request.query_string if request.query_string else ''))) 
     return decorator 
    return requireAuthentication 
Смежные вопросы