rest_framework提供了几种认证方式:Session、Token等。Session是最简单的,几乎不用写任何代码就可以是实现,Token方式其实也不复杂,网上的教程一大把,但是最后都是用Postman这类工具来实现API调用的,通过这类工具来增加HTTP头信息以回传Token。那么真正的前端网页应该怎么办呢?网上基本上就是基于Aixos来实现的,但是我就不想用Vue,纯Javascript是不能改写HTTP头的。怎么办?
首先,看一下TokenAuthentication的源码:
auth = request.META.get('HTTP_AUTHORIZATION', b'')
它是从HTTP头中读取Authorization,其中是的内容Token(固定字) Token(值)。
那既然JavaScript不能改写头,但是能用cookie啊,所以我就通过自定义TokenAuthentication类,读取Cookie来实现。
-
用户登录之后先创建Token,并返回给前端。
-
前端把Token保存到Cookie。
$.ajax({
url: "login",
type:'POST',
data: {'username':username,'password':password},
dataType: "json",
success: function (data) { //请求成功后执行的操作
if (data.status == "SUCCESS") {
//localStorage.setItem('token',data.token);
$.cookie('token', data.token);
window.location.href = '/';
}
else{
alert('Invalid username or password.');
}
}
});
这样每次发起HTTP请求时都会把Token带上
- 在logout的时候把Token删除。防止失效Token仍然可以使用。
def logout_view(request):
request.user.auth_token.delete()
logout(request)
return redirect('login')
- 写一个自定义的TokenAuthentication类:
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authtoken.models import Token
class CustomTokenAuthentication(BaseAuthentication):
keyword = 'token'
def authenticate(self, request):
cookie_token = request.COOKIES.get(self.keyword)
if cookie_token is None:
raise AuthenticationFailed('No Token Found in Cookies!')
try:
user_token = Token.objects.get(key=cookie_token)
if user_token is None:
raise AuthenticationFailed('No Token Found for Current User!')
return (user_token.user, user_token)
except Token.DoesNotExist:
raise AuthenticationFailed('Token in cookie is invalidate!')
当Token未提供或者无效时,直接抛出AuthenticationFailed异常
- 讲自定义的类放入项目的settings,否则不生效:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'bid_request_system_app.commons.authentications.CustomTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
- 在相对应的view方法前面加上相应的注解:
@api_view(['GET', 'POST'])
@csrf_exempt
@login_required()
@authentication_classes([CustomTokenAuthentication])
@permission_classes([IsAuthenticated, IsAdminUser])
def department_management_view(request):
这样的话就OK了。