Django使用一次调用函数输出作为全局值

时间:2018-01-28 11:27:18

标签: python django api server

在初始化项目时,我想从项目设置中调用登录功能一次,并在项目中的任何位置使用输出令牌。我想使用相同的令牌是否再次调用以检查令牌是否已更改。

def login(creds):
    r = requests.post(base_url + '/api/admin/login', json=creds, headers=headers, verify=False)
    if r.status_code == 200:
        token = r.json()['token']
        return token

如果我在项目设置中调用函数,则每次都会启动函数。我不想将令牌转储到文件并每次都读取。还有其他方法吗?谢谢。

1 个答案:

答案 0 :(得分:0)

最好的方法是分离登记,身份验证和令牌使用的责任。实际上,你会在会话中存储令牌。 Django为匿名会话提供完全支持,但是如果您希望将与该用户关联的一些数据存储在本地数据库中,这可能会限制您的应用程序。

我建议在用于保存用户名的本地数据库中设置用户模型。接下来,您将创建一个身份验证功能:

import requests

def authentication(username, password):
    creds = {'username': username, 'password': password}
    headers = 'whatever'
    r = requests.post(base_url + '/api/admin/login', json=creds, headers=headers, verify=False)
    if r.status_code == 200:
        token = r.json()['token']
        # Create user in the local database if it does not exist yet
        user, created = User.objects.get_or_create(username=username)
        return token
    else:
        error = 'Something went wrong'
        return error

接下来,您将创建登录功能。

from django.urls import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth import login
from django.shortcuts import render

def login(request):

    # Check if user is authenticated by call is_authenticated() and
    # additionally check if token is stored in session
    if request.user.is_authenticated and request.session.get('token', False):
        return HttpResponseRedirect(reverse('user_page'))

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        auth_data = authenticate(username=username, password=password)

        if auth_data is not None:
            # Save token in session
            request.session['user_token'] = auth_data
            # Get user and login
            # Because you created a user in local database, 
            # you can login that user in this step
            user = User.objects.get(username=username)
            login(request, user)
            next = request.POST.get('next', '/') if request.POST.get('next') else '/'
            return HttpResponseRedirect(next)
       else:
            # Implement some error handling here
            return HttpResponseRedirect(reverse('login'))
    else:
        return render(request, 'login.html', {})

下一个合乎逻辑的步骤是以某种方式控制这些用户令牌。装饰员来救援。您创建一个检查令牌的装饰器。例如,在这个意义上的东西:

import functools
from django.contrib.auth import REDIRECT_FIELD_NAME
from urllib.parse import urlparse
from django.shortcuts import resolve_url
from django.contrib.auth.views import redirect_to_login

def token_required(func, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):

    @functools.wraps(func)
    def decorated_function(request, *args, **kwargs):
        # Check if token is saved in session
        # Redirect to login page if not
        if not request.session.get('token', False):
            path = request.build_absolute_uri()
            resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
            # If the login url is the same scheme and net location then just
            # use the path as the "next" url.
            login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
            current_scheme, current_netloc = urlparse(path)[:2]
            if ((not login_scheme or login_scheme == current_scheme) and
                (not login_netloc or login_netloc == current_netloc)):
                path = request.get_full_path()           
            return redirect_to_login(
                path, resolved_login_url, redirect_field_name)
        return func(request, *args, **kwargs)
    return decorated_function

你需要在这里实现你的逻辑。这个装饰器只检查令牌是否存储在会话中,没有别的。然后,您将在视图中使用此装饰器,如

from django.contrib.auth import logout

@token_required
@login_required
def user_logout(request):   
    logout(request)
    return HttpResponseRedirect('/')