假设用户在https://example.com/any/page?token=hhdo28h3do782上登陆。
使用查询字符串对用户进行身份验证和登录的推荐方法是什么?
我正在考虑创建一个调用authenticate()的完全捕获视图(我也想知道如何做到这一点:D)。然后,我将设置一个自定义后端来验证用户。
这是实现我想要的理想的方式吗?
干杯!
发布于 2020-05-26 15:16:31
为此,您需要验证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现在,除了已有的任何后端或中间件之外,您还可以在AUTHENTICATION_BACKENDS和MIDDLEWARE中添加到settings.py的路径。如果使用的是默认值,则如下所示:
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",
]发布于 2020-05-26 14:47:17
我假设您正在使用Django REST框架,并且在您的项目中启用了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,您必须编写自定义模型后端(这是一个有点长的主题)。
参考:编写身份验证后端
发布于 2020-05-26 14:57:03
所以,从一种管理令牌的方法开始。下面是一个基本模型:
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 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)https://stackoverflow.com/questions/62024580
复制相似问题