1.token登录实现
参考django restframework文档关于TokenAuthentication
。
1.1 在setting.py中加入authtoken
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
REST_FRAMEWORK = {
# 用于验证用户登录信息
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
]
}
1.2 迁移关于token相关数据表
- python manage.py makemigrations
-
python manage.py migrate
1.3 url.py中配置路由
from rest_framework.authtoken import views
urlpatterns += [
path('api-token-auth/', views.obtain_auth_token)
]
1.4 postman测试接口
2.登录原理
通过接口获取token实现
class ObtainAuthToken(APIView):
....
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
# 查询authtoken_token表中的token.key
# 如果没有则插入数据
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key})
obtain_auth_token = ObtainAuthToken.as_view()
通过token进行接口验证
# rest_framework/authentication.py
class TokenAuthentication(BaseAuthentication):
keyword = 'Token'
model = None
def get_model(self):
if self.model is not None:
return self.model
from rest_framework.authtoken.models import Token
return Token
def authenticate(self, request):
# 获取token(Token ff000224e411d7676cc1e0da2d0a1ace6c372df1)并分割
auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != self.keyword.lower().encode():
return None
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Token string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
# token为ff000224e411d7676cc1e0da2d0a1ace6c372df1
token = auth[1].decode()
except UnicodeError:
msg = _('Invalid token header. Token string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
def authenticate_credentials(self, key):
# 获取表authtoken_token的模型
model = self.get_model()
try:
# 校验用户的token是否存在或有效
token = model.objects.select_related('user').get(key=key)
except model.DoesNotExist:
raise exceptions.AuthenticationFailed(_('Invalid token.'))
if not token.user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
return (token.user, token)
3.缺点
- token是永久的,没有过期时间,泄漏会有问题
- 分布式的应用,需要同步用户信息到每个服务器