每日分享
What you seek is seeking you.
你所寻找的东西其实也正在寻找你。
美多商城项目(二)
1.注册信息的保存
1.1 接口设计
创建一个新用户
API: POST /users/ 参数: { "username":"用户名", "password":"密码", "password2":"重复密码", "mobile":"手机号", "sms_code":"短信验证码", "allow":"是否同意用户协议", # 'true'同意 } 响应: { 'id':'用户ID', 'username':'用户名', 'mobile':'手机号', 'token':'jwt token' }
注册用户信息的保存:
1.获取参数进行校验(参数完整性,是否同意协议,手机号格式,手机号是否已经注册过,两次密码是否一致,短信验证码是否正确)
2.创建新用户并保存到数据库。
3.注册成功,将新用户序列化并返回。
1.2注意小点
1.序列化器类定义时的参数
write-only 只在反序列化时使用 read-only 只在序列化时使用
上面的 write-only
和 read-only
默认都是False,我们可以针对我们的需求对这两个参数进行设置。
2.补充验证:
a.在字段中添加 validators
选项参数
b.对 <field_name>
字段进行验证
c.在序列化器中需要同时对多个字段进行比较验证时,可以定义 validate
方法来验证。
3.redis中存的数据,无论是什么格式,取出来的都是 bytes
类型,所以按需求要进行解码 decode
2.JWT认证机制
2.1session认证机制:
用户登录: 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中数据更加安全
2.2JWT认证机制
用户登录: 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传递给服务器之后,服务器首先需要进行签名认证,签名验证的过程:
- 将客户端传递的jwt token中的header和payload字符串进行拼接,用
.
隔开 - 使用服务器之间的密钥对拼接之后的字符串进行加密
- 将加密之后的内容和将客户端传递的jwt token中signature进行对比,如果不一致,就说明jwt token是被伪造的。
注意点:
a.payload不要存放一些敏感数据
b.服务器密钥需要保持好,
c.如果可以,使用HTTPS协议。
2.3JWT 扩展
功能:生成jwt token,也能检验jwt token。
3.用户登录
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' }
3.2登录账户支持手机号和用户名
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认证后端类']
3.2QQ登录
效果:
当使用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 |
3.1小知识点
1.我们可以将JWT保存在cookie中,也可以保存在浏览器的本地存储里,我们保存在浏览器本地存储中。
2.浏览器的本地存储提供了sessionStorage 和 localStorage 两种:
- sessionStorage 浏览器关闭即失效
- localStorage 长期有效
3.『记住登录』这个小功能是在前端完成的。如果记住密码,就保存在localStorage中,不记住密码,就将其保存在sessionStorage中。