在进行用户登陆验证的时候,如果是自己写代码,就必须要先查询数据库,看用户输入的用户名是否存在于数据库中;
如果用户存在于数据库中,然后再验证用户输入的密码,这样一来就要自己编写大量的代码。
事实上,Django已经提供了内置的用户认证功能。
有时候我们需要用到邮箱或者手机登录而不只是用户名,所以需要自己重写功能,在utils文件夹里创建一个文件utils.py里面写:
#当前文件夹里面,定义的是自定义的认证系统
from django.contrib.auth.backends import ModelBackend
import re
from user import models
'''Django自带的认证系统
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user'''
'''当前的类,是用来定义的认证方法'''
class UserPhoneEmailAuthBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
'''
:param request:
:param username:可能是手机号码/邮箱/用户名
:param password:
:param kwargs:
:return:
'''
#1. todo 不管是用户或者邮箱或者手机号码,第一件事获取对象
try:
#todo 先通过正则,判断出手机号码/用户名/邮箱
if re.match(r'^1[\d]{10}$',username):
user = models.User.objects.get(phone=username)
print('111111111111111111eeeeeeeeerrrrrrrrrrrrrrrrr')
elif re.match('^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$',username):
user = models.User.objects.get(email=username)
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
直接在对应的urls.py里配置即可
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
url(r'^login/',obtain_jwt_token),
]
通过ajax请求发送用户名和密码。验证成功后会得到token。
然后把token存到localStorage,这个是固定存储网页关闭了也存在,在设置.py里可以设置过期时间。
$(function () {
$('#llogin').click(function () {
//获取用户名和密码
//用户名
var username = $('#lusername').val();
var password = $('#lpassword').val();
//拼接json数据向后端传递数据
var data = {
'username':username,
'password':password
};
//将对象转成json数据
data_json = JSON.stringify(data)
//发送
$.ajax({
url:'http://127.0.0.1:8000/user/login/',
type:'POST',
data:data_json,
contentType:'application/json',
dataType:'json',
success:function (data) {
alert(data)
console.log(data);
//清空token
localStorage.clear();
//储存token
localStorage.token=data['token'];
//返回到前端
console.log( '返回到前端');
console.log( localStorage.token)
},
error:function (data){
alert('请求失败')
}
})
})
});
因为默认使用的返回只有token,我们需要更多地内容比如username和id,当然也可以前端解析base64来实现,这里使用后端重写来返回更多内容。
还是在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
然后在自己的设置文件里配置,我的是dev.py,添加这个配置路径也就是第二个键值对
# 设置过期时间和jwt返回值
JWT_AUTH = {
#jwt过期时间
#'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=60),
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
#配置自定义jwt返回内容
'JWT_RESPONSE_PAYLOAD_HANDLER':'shanghui.utils.utils.jwt_response_username_userid_token'
}
这时候前端访问即可得到:
Object {user_id: 21, token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1N…ExIn0.6IEeAsMgg_qRCivw0ErmLqvYmlvVF7ckvpxjNmdfUGs", username: "1111"}
fields里面填需要的值就行,我在models添加了一些值,便于修改
class LodinUserInfoSerializer(serializers.ModelSerializer):
''''email
为了偷懒直接用
'''
class Meta:
model = models.User
fields = ('id','username','phone','email')
这个导的是RetrieveUpdateAPIView,可以实现get和put请求
class LodinUserInfoView( RetrieveAPIView):
'''用户信息返回给前端'''
# 1.指定序列化器
serializer_class = serializers.LodinUserInfoSerializer
# todo 进行权限的指定
#两种都可以
permission_classes = (IsAuthenticated,)
#permission_classes = [IsAuthenticated]
# 2.指定单个模型
def get_object(self):
print('=================================')
print(self.request.user)
return self.request.user
这是用户信息界面,get请求需要添加请求头设置:
$(function () {
token = localStorage.token
// alert(token)
//get()等价于ajax({})
$.ajax({
url:'http://127.0.0.1:8000/user/userinfo/',
method:'GET',
headers:{
//‘JWT ’里面必须带空格
'Authorization':'JWT '+ token
},
success:function (data) {
// alert('ok');
console.log(data);
console.log( '返回到前端');
console.log( localStorage.token);
//替换用户名
email = data['email'];
username = data['username'];
phone = data['phone'];
console.log(email,phone,username);
$('#uusername').html(username);
$('#uusername1').val(username);
$('#uemail').val(email);
$('#uphone').val( phone)
},
error:function (data) {
console.log(data);
console.log('error');
console.log(data['status']);
if (data['status']==401){
location.href = 'http://127.0.0.1:8080/templates/login.html'
}
// alert('失败');
}
});
});
其实和GET是一样的,要注意添加请求头即可
$('#btn').click(function () {
$.ajax({
url:'http://127.0.0.1:8000/user/email/',
headers:{
//‘JWT ’里面必须带空格
'Authorization':'JWT '+ token
},
type:'PUT',
id:'',
//email:'[email protected]',
data:{
_method:'PUT',
"email":'[email protected]'
},
dataType:'json',
success:function (data) {
alert('ok');
console.log(data);
console.log( '返回到前端');
console.log( localStorage.token);
替换用户名
email = data['email'];
username = data['username'];
phone = data['phone'];
console.log(email,phone,username);
$('#uusername').html(username);
$('#uusername1').val(username);
$('#uemail').val(email);
$('#uphone').val( phone)
},
error:function (data) {
console.log(data);
console.log('error');
console.log(data['status']);
if (data['status']==401){
location.href = 'http://127.0.0.1:8080/templates/login.html'
}
// alert('失败');
$.ajax({
url:'http://127.0.0.1:8000/user/email/',
method:'PUT',
headers:{
//‘JWT ’里面必须带空格
'Authorization':'JWT '+ token
},
success:function (data) {
// alert('ok');
console.log(data);
console.log( '返回到前端');
console.log( localStorage.token);
替换用户名
email = data['email'];
username = data['username'];
phone = data['phone'];
console.log(email,phone,username);
$('#uusername').html(username);
$('#uusername1').val(username);
$('#uemail').val(email);
$('#uphone').val( phone)
},
error:function (data) {
console.log(data);
console.log('error');
console.log(data['status']);
if (data['status']==401){
location.href = 'http://127.0.0.1:8080/templates/login.html'
}
// alert('失败');
}
})
});