如何使用任何 url 上的查询参数对用户进行身份验证?
How can I authenticate a user with a query parameter on any url?
假设用户登陆 https://example.com/any/page?token=hhdo28h3do782
。
使用查询字符串对用户进行身份验证和登录的推荐方法是什么?
我正在考虑创建调用 authenticate()
的某种包罗万象的视图(我也想知道如何执行此操作 :D)。然后我会建立一个自定义后端来验证用户。
这是实现我想要的理想方式吗?
干杯!
我假设您正在项目中使用 Django REST Framework and also enabled the TokenAuthentication 机制。如果是这样,请继续,
from rest_framework.authentication import TokenAuthentication
class QueryParamAuthentication(TokenAuthentication):
query_param_name = 'token'
def authenticate(self, request):
token = request.query_params.get(self.query_param_name)
if token:
return self.authenticate_credentials(token)
return None
然后,将 DRF DEFAULT_AUTHENTICATION_CLASSES
更改为
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'dotted.path.to.QueryParamAuthentication'
),
# rest of your DRF settings...
}
更新
要在没有 DRF 的情况下执行此操作,您必须编写自定义模型后端(这是一个有点冗长的主题)
所以,从管理您的代币开始。这是一个基本模型:
class Token(models.Model):
code = models.CharField(max_length=255)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
expires = models.DateTimeField()
可以生成自定义身份验证后端来检查令牌的有效性:
class TokenAuthenticationBackend(ModelBackend):
def authenticate(self, request, token=None):
try:
token = Token.objects.get(code=token, expires__gte=now())
except Token.DoesNotExist:
return None
else:
return token.user
如果您使用的是基于 class 的视图,您可以编写一个 mixin 来检查令牌是否存在,然后执行您的身份验证逻辑:
class UrlTokenAuthenticationMixin:
def dispatch(self, request, *args, **kwargs):
if 'token' in request.GET:
user = authenticate(request, request.GET['token'])
if user:
login(request, user)
return super(UrlTokenAuthenticationMixin, self).dispatch(request, *args, **kwargs)
要在给定视图上使用它,只需按如下方式声明您的视图:
class MyView(UrlTokenAuthenticationMixin, TemplateView):
# view code here
例如
将此实现为一揽子包罗万象的另一种方法是使用中间件而不是混合:
class TokenAuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if 'token' in request.GET:
user = authenticate(request, request.GET['token'])
if user:
login(request, user)
return self.get_response(request)
为此,您需要 create a custom authentication backend 验证 api 键。
在此示例中,request
自动检查有效令牌。您根本不需要修改您的观点。这是因为它包含对用户进行身份验证的自定义中间件。
为简洁起见,我假设有效的用户令牌存储在一个模型中,该模型是外键到 django auth.User
模型。
# my_project/authentication_backends.py
from django.contrib import auth
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.contrib.auth.middleware import AuthenticationMiddleware
TOKEN_QUERY_PARAM = "token"
class TokenMiddleware(AuthenticationMiddleware):
def process_request(self, request):
try:
token = request.GET[TOKEN_QUERY_PARAM]
except KeyError:
# A token isn't included in the query params
return
if request.user.is_authenticated:
# Here you can check that the authenticated user has the same `token` value
# as the one in the request. Otherwise, logout the already authenticated
# user.
if request.user.token.key == token:
return
else:
auth.logout(request)
user = auth.authenticate(request, token=token)
if user:
# The token is valid. Save the user to the request and session.
request.user = user
auth.login(request, user)
class TokenBackend(ModelBackend):
def authenticate(self, request, token=None):
if not token:
return None
try:
return User.objects.get(token__key=token)
except User.DoesNotExist:
# A user with that token does not exist
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
现在,除了您可能已经拥有的任何现有后端或中间件之外,您还可以在 settings.py
中添加 AUTHENTICATION_BACKENDS
和 MIDDLEWARE
的路径。如果您使用的是默认值,它将如下所示:
MIDDLEWARE = [
# ...
"django.contrib.auth.middleware.AuthenticationMiddleware",
# This is the dotted path to your backend class. For this example,
# I'm pretending that the class is in the file:
# my_project/authentication_backends.py
"my_project.authentication_backends.TokenMiddleware",
# ...
]
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"my_project.authentication_backends.TokenBackend",
]
假设用户登陆 https://example.com/any/page?token=hhdo28h3do782
。
使用查询字符串对用户进行身份验证和登录的推荐方法是什么?
我正在考虑创建调用 authenticate()
的某种包罗万象的视图(我也想知道如何执行此操作 :D)。然后我会建立一个自定义后端来验证用户。
这是实现我想要的理想方式吗?
干杯!
我假设您正在项目中使用 Django REST Framework and also enabled the TokenAuthentication 机制。如果是这样,请继续,
from rest_framework.authentication import TokenAuthentication
class QueryParamAuthentication(TokenAuthentication):
query_param_name = 'token'
def authenticate(self, request):
token = request.query_params.get(self.query_param_name)
if token:
return self.authenticate_credentials(token)
return None
然后,将 DRF DEFAULT_AUTHENTICATION_CLASSES
更改为
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'dotted.path.to.QueryParamAuthentication'
),
# rest of your DRF settings...
}
更新
要在没有 DRF 的情况下执行此操作,您必须编写自定义模型后端(这是一个有点冗长的主题)
所以,从管理您的代币开始。这是一个基本模型:
class Token(models.Model):
code = models.CharField(max_length=255)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
expires = models.DateTimeField()
可以生成自定义身份验证后端来检查令牌的有效性:
class TokenAuthenticationBackend(ModelBackend):
def authenticate(self, request, token=None):
try:
token = Token.objects.get(code=token, expires__gte=now())
except Token.DoesNotExist:
return None
else:
return token.user
如果您使用的是基于 class 的视图,您可以编写一个 mixin 来检查令牌是否存在,然后执行您的身份验证逻辑:
class UrlTokenAuthenticationMixin:
def dispatch(self, request, *args, **kwargs):
if 'token' in request.GET:
user = authenticate(request, request.GET['token'])
if user:
login(request, user)
return super(UrlTokenAuthenticationMixin, self).dispatch(request, *args, **kwargs)
要在给定视图上使用它,只需按如下方式声明您的视图:
class MyView(UrlTokenAuthenticationMixin, TemplateView):
# view code here
例如
将此实现为一揽子包罗万象的另一种方法是使用中间件而不是混合:
class TokenAuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if 'token' in request.GET:
user = authenticate(request, request.GET['token'])
if user:
login(request, user)
return self.get_response(request)
为此,您需要 create a custom authentication backend 验证 api 键。
在此示例中,request
自动检查有效令牌。您根本不需要修改您的观点。这是因为它包含对用户进行身份验证的自定义中间件。
为简洁起见,我假设有效的用户令牌存储在一个模型中,该模型是外键到 django auth.User
模型。
# my_project/authentication_backends.py
from django.contrib import auth
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.contrib.auth.middleware import AuthenticationMiddleware
TOKEN_QUERY_PARAM = "token"
class TokenMiddleware(AuthenticationMiddleware):
def process_request(self, request):
try:
token = request.GET[TOKEN_QUERY_PARAM]
except KeyError:
# A token isn't included in the query params
return
if request.user.is_authenticated:
# Here you can check that the authenticated user has the same `token` value
# as the one in the request. Otherwise, logout the already authenticated
# user.
if request.user.token.key == token:
return
else:
auth.logout(request)
user = auth.authenticate(request, token=token)
if user:
# The token is valid. Save the user to the request and session.
request.user = user
auth.login(request, user)
class TokenBackend(ModelBackend):
def authenticate(self, request, token=None):
if not token:
return None
try:
return User.objects.get(token__key=token)
except User.DoesNotExist:
# A user with that token does not exist
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
现在,除了您可能已经拥有的任何现有后端或中间件之外,您还可以在 settings.py
中添加 AUTHENTICATION_BACKENDS
和 MIDDLEWARE
的路径。如果您使用的是默认值,它将如下所示:
MIDDLEWARE = [
# ...
"django.contrib.auth.middleware.AuthenticationMiddleware",
# This is the dotted path to your backend class. For this example,
# I'm pretending that the class is in the file:
# my_project/authentication_backends.py
"my_project.authentication_backends.TokenMiddleware",
# ...
]
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"my_project.authentication_backends.TokenBackend",
]