JWT的初步使用之重写自带的用户认证
官方文档:https://yiyibooks.cn/xx/Django_1.11.6/topics/auth/index.html
jwt 的初步应用流程:
- 用户登录或者注册账号,携带用户名和密码,传到服务器。
- 服务器利用前端传送来的信息,生成 jwt 命令。
- 服务器将jwt返回给前端浏览器。
- 如果用户进行访问,将携带jwt去访问后端服务器。
- 服务器将接收到的jwt令牌进行校验,如果校验通过,就可以返回用户信息等。
- 前端接收到后端发来的数据,然后在页面显示出来。
为何要自己重写认证登录
Django提供的内置的用户认证功能,只能单一的验证一种用户名,而现在有些网址可以支持多种用户名登录,如邮箱、手机号码,此时,我们就需要使用重写认证登录。
在utils文件夹里创建一个utils.py文件,然后编写内容为:
# 当前文件夹里面,定义的是自定义的认证系统
import re
from users import models
from django.contrib.auth.backends import ModelBackend
# 自定义认证方法
class UserPhoneEmailAuthBackend(ModelBackend):
''' 当前的类,是用来定义自定义的认证方法'''
def authenticate(self, request, username=None, password=None, **kwargs):
'''
重写父类的方法
:param request:
:param username: 用户名、手机号码、邮箱
:param password:
:param kwargs:
:return:
'''
# todo 不管是用户或者邮箱或者手机号码,第一件事情,是获取对象
try:
# todo 先通过正则,判断出手机号码
if re.match(r'^1[3456789]\d{9}$', username):
user = models.User.objects.get(phone=username)
# todo 邮箱
elif re.match(r'^[\w]+@[\w]+\.com$', username):
user = models.User.objects.get(email=username)
# todo 用户名
else:
user = models.User.objects.get(username=username)
except models.User.DoesNotExist:
user = None
# todo 拿到user之后 进行校验
if user is not None and user.check_password(password):
return user
在settings配置文件里添加:
#配置自定义的认证
AUTHENTICATION_BACKENDS = [
# 默认值:['django.contrib.auth.backends.ModelBackend']
'shanghuiproject.utils.utils.UserPhoneEmailAuthBackend',
]
jwt自带的验证视图
直接在对应的urls.py文件里配置:
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
url(r'^login/$',obtain_jwt_token), # 登录验证
]
重写jwt的返回内容
因为默认返回的内容只有token,有时我们需要得到更多的信息,如用户名,id等。
还是在utils文件夹里的utils.py文件里编写内容:
# 认证成功后,返回给前端的自定义数据处理方法
def jwt_response_username_userid_token(token,user=None,request=None):
'''
JWT登录成功之后,自定义的返回数据的处理,
:param token:
:param user:
:param request:
:return:
'''
data = {
'token': token,
'username': user.username,
'user_id': user.id,
}
return data
然后在settings.py文件下添加上面内容的路径:
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=200), # 过期时间
# 配置自定义的jwt返回内容路径
'JWT_RESPONSE_PAYLOAD_HANDLER': 'shanghuiproject.utils.utils.jwt_response_username_userid_token',
}
前端的登录按钮触发的ajax请求
前端点击按钮就会把用户名和密码通过ajax发送给后端,后端接收到数据,验证成功后会返回一个token,然后前端通过success回调函数将数据token进行保存。
$('#usersubmit').click(function () {
var usernmae = $('#userloginname').val();
var userpwd = $('#loginpwd').val();
var data = {
'username': usernmae,
'password': userpwd,
};
data = JSON.stringify(data);
$.ajax({
url: 'http://127.0.0.1:8000/users/login/',
method: 'POST',
contentType: 'application/json',
data: data,
success:function (data) {
console.log(data);
token = data['token'];
localStorage.clear();
// sessionStorage.token = token; //浏览器关闭就失效
localStorage.token = token; //长期有效
console.log('从本地获取的token',localStorage.token);
location.href = 'http://127.0.0.1:8080/templates/userinfo.html'
},
error: function (data) {
console.log(data);
}
})
})
前端返回结果:
JWT 如何返回用户信息
在serilizers.py文件下写一个序列器:
fields里面的元组只要填自己需要用到的字段就好
class LoginUserInfoSerilaizer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ('id','username','phone','email',)
在view.py文件编写视图类:
RetrieveAPIView视图里面自带put请求和get请求,get_object()返回的是单个模型。
class LoginUserInfoView(RetrieveAPIView):
'''
前端GET请求:将用户信息返回给前端
'''
# 1.需要指定序列化器
serializer_class = serializers.LoginUserInfoSerilaizer
# 2.指定单个模型
def get_object(self):
print(self.request.user)
return self.request.user
在 urls.py 文件的内容:
urlpatterns = [
url(r'^userinfo/$',views.LoginUserInfoView.as_view()),
]
前端通过get请求发送JWT值然后获取后端传送来的信息
最重要的是在前端的Ajax中需要添加下面代码:
注意:下面代码中JWT后面有一个空格
headers:{
'Authorization':'JWT ' + token
},
整个ajax请求代码:
$.ajax({
url: 'http://127.0.0.1:8000/users/userinfo/',
method:'GET',
headers:{
'Authorization':'JWT ' + token
},
success: function (data) {
console.log(data);
console.log('token',token);
email = data['email'];
phone = data['phone'];
username = data['username'];
console.log(email, phone, username);
//在前端设置相对于的值
$('.myusername').html(username).val(username);
$('#myemail').val(email);
$('#myphone').val(phone);
},
error: function (data) {
console.log(data);
console.log(data['status']);
// 如果是401(JWT过期)错误,就跳转到登录界面
if (data['status']==401){
//location.href = 'http://127.0.0.1:8080/templates/login.html';
location.href = '/templates/login.html?next=/userinfo.html'
}
}
});