What you seek is seeking you.
你所寻找的东西其实也正在寻找你。
创建一个新用户
API: POST /users/
参数:
{
"username":"用户名",
"password":"密码",
"password2":"重复密码",
"mobile":"手机号",
"sms_code":"短信验证码",
"allow":"是否同意用户协议", # 'true'同意
}
响应:
{
'id':'用户ID',
'username':'用户名',
'mobile':'手机号',
'token':'jwt token'
}
注册用户信息的保存:
1.获取参数进行校验(参数完整性,是否同意协议,手机号格式,手机号是否已经注册过,两次密码是否一致,短信验证码是否正确)
2.创建新用户并保存到数据库。
3.注册成功,将新用户序列化并返回。
1.序列化器类定义时的参数
write-only 只在反序列化时使用
read-only 只在序列化时使用
上面的 write-only
和 read-only
默认都是False,我们可以针对我们的需求对这两个参数进行设置。
2.补充验证:
a.在字段中添加 validators
选项参数
b.对 <field_name>
字段进行验证
c.在序列化器中需要同时对多个字段进行比较验证时,可以定义 validate
方法来验证。
3.redis中存的数据,无论是什么格式,取出来的都是 bytes
类型,所以按需求要进行解码 decode
用户登录:
1.接收参数并进行校验(将用户名和密码校验)
2.检验用户名和密码是否正确
3.保存用户的登录信息
session['user_id'] = 2
session['username'] = 'ethanyan'
session['mobile'] = '13288888888'
4.返回应答,登录成功
在返回应答时,会让客户端保存cookie和sessionid( 客户端session信息标识
),在之后客户端访问服务器时,就会携带sessionid,服务器就可以根据sessionid取出对应的session信息并对用户登录的状态进行判断。
session认证机制存在问题:
a.session数据存储服务器,如果登录用户过多,会过多占用服务器存储空间。
b.session是依赖于cookie的,如果cookie被截获,可能会造成CSRF伪造。
c.对于分布式网站应用中,如果session存储在内存中,session的共享会产生问题。(在网站部署的时候,有很多服务器运行着,某台服务器内存中存着一位用户的session,其他服务器中是没有的。Nginx在转发的时候,有可能下次交给了其他服务器处理该用户的请求,然后就没有了给用户的一些信息,比如登录状态。)
优点:
a.存储在session中数据更加安全
用户登录:
1.接收参数并进行校验(将用户名和密码校验)
2.检验用户名和密码是否正确
3.由服务器生成一个字符串(jwt token),保存了登录用户的身份信息
公安局(服务器)--->身份证(jwt token)
4.返回响应时,需要将jwt token返回给客户端
客户端需要将jwt token保存下来,然后在请求服务器时,如果需要对用户的身份进行认证,客户端则需要将jwt token传递给服务器,由服务器对jwt token进行校验,来对用户进行认证。
优点:
a.jwt token是由客户端进行保存的,不会占用服务器存储空间。
缺点:
a.因为jwt token是存储在客户端,所以jwt token不建议存放一些敏感数据。
jwt token字符串格式:
是一个字符串,由三部分组成,用 .
隔开
a.header(头部)
{
"token类型",
"signature签名加密算法",
}
使用base64对头部信息进行加密( 编码
),加密之后生成的字符串就是header内容。
b.payload(载荷)
存储的是有效数据
{
"user_id":"用户id",
"username":"用户名",
"email":"邮箱",
"exp":"token有效时间"
...
}
上面的exp(token有效期)是UTC时间,我们采用的北京时间相比是领先8个小时的。
使用base64对载荷信息进行加密( 编码
),加密之后生成的字符串就是payload内容。
c.signature(签名)
作用:防止将jwt token被伪造
1.签名的生成过程
答:服务器在生成jwt token时,会将header和payload字符串进行拼接,用 .
隔开,然后使用一个只有服务器知道的密钥对拼接后的内容进行加密,加密之后生成的字符串就是signature内容。
2.签名验证过程?
答:当客户端将jwt token传递给服务器之后,服务器首先需要进行签名认证,签名验证的过程:
.
隔开注意点:
a.payload不要存放一些敏感数据
b.服务器密钥需要保持好,
c.如果可以,使用HTTPS协议。
功能:生成jwt token,也能检验jwt token。
API:POST /authorizations/
参数:
{
"username":"用户名",
"password":"密码"
}
响应:
{
"user_id":"用户ID",
"username":"用户名",
"token":"jwt token"
}
jwt扩展中提供了一个登录视图 obtain_jwt_token
这个登录视图就是接收username和password,并对账户名和密码进行校验,校验通过之后会生成一个jwt token,并在响应时返回。
自定义jwt扩展登录视图相应数据的函数:
def jwt_response_payload_handler(token,user=None,request=None):
"""
自定义jwt扩展登录视图的响应数据函数
"""
return {
'user_id':user.id,
'username':user.username,
'token':token
}
配置:
# JWT扩展配置
JWT_AUTH = {
# 设置JWT的有效时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
# 指定jwt扩展登录视图响应数据函数
'JWT_RESPONSE_PAYLOAD_HANDLER':
'users.utils.jwt_response_payload_handler'
}
1. obtain_jwt_token
登录视图中没有自己实现账户名和密码校验的代码,而是调用了Django认证系统中一个函数进行账户和密码的校验。
2.认证系统中的 authenticate
from django.contrib.auth import authenticate
而 authenticate
方法内容也没有自己实现账户和密码校验的代码,而是调用Django认证后端类中 authenticate
进行账户和密码的校验。
3.Django认证后端类
from django.contrib.auth.backends import ModelBackend
在 ModelBackend
类中 authenticate
最终实现了账户和密码校验代码,但是账户仅支持用户名。
自定义Django认证后端类:
class UsernameModelAuthBackend(ModelBackend):
def authenticate(self,request,username=None,password=None,**kwargs):
"""
username既可以传递用户名也可以传递手机号
username:用户名或者手机号
password:密码
"""
# 根据用户名或手机号查询用户的信息
pass
# 如果用户存在,再校验密码
pass
指定Django认证后端类:
AUTHENTICATION_BACKENDS = ['自定义Django认证后端类']
效果:
当使用QQ账户登录的时候,会判断QQ账户和网站用户是否进行绑定,如果已经绑定过,则会直接让对应的用户登录成功;如果还没有绑定过,会先让用户进行绑定操作,只有绑定之后才能跳转到首页,登录成功。
预备工作:
a.注册成功QQ的开发者。
b.登录开发者账户,创建开发者应用,提交相关的信息并等待审核。
c.审核通过,获取 appid
和 appkey
,就可以进行QQ相关功能开发。
开发关键点:
a.QQ用户的 openid
:QQ账户的唯一标识。
b.获取QQ登录用户的openid,判断openid和网站的用户是否进行了绑定,如果已经进行了绑定,直接让对应的用户登录成功;如果没有绑定,则将openid和对应网站用户进行绑定。
c.一个账户可以绑定多个QQ。如下示例:
id | openid | user_id |
---|---|---|
1 | AFAJDFfjafjafjFADFJ123FFSA | 2 |
2 | DAFJFsfdafF3442JKKJfsadfaf | 2 |
1.我们可以将JWT保存在cookie中,也可以保存在浏览器的本地存储里,我们保存在浏览器本地存储中。
2.浏览器的本地存储提供了sessionStorage 和 localStorage 两种:
3.『记住登录』这个小功能是在前端完成的。如果记住密码,就保存在localStorage中,不记住密码,就将其保存在sessionStorage中。
优质文章推荐: