每日分享
If you saw the darkness in front of you, don't be afraid, that's because sunshine is at your back.
如果你看到了身前的黑暗,请不要害怕,因为你身后定是阳光。
小闫语录:
我们背对太阳,面前一片黑暗,转身便尽是阳光。
美多商城项目(十一)
项目仓库地址
https://github.com/EthanYan6/E-commerce-sites.git
1.重置密码
API: PUT /users/(?P<pk>\d+)/password/ 参数: { "old_password":"用户旧密码", "password":"用户修改后密码", "password2":"用户确认密码" } 响应: { "message":"OK" }
1.1业务逻辑
1.获取参数并校验,看原密码是否正确,两次密码是否一致。
2.更新数据到数据库。
3.返回响应。
1.2功能补充说明
1.可以在前端添加两次密码是否一致的校验,也可以在后端添加。
2.可以在前端页面的js文件中添加原密码校验失败之后的报错信息,可以根据状态码指定,也可以直接判断指定。
3.当在个人中心修改完密码之后,直接跳转登录页面使其重新登录。
2.订单列表获取
用户中心点击全部订单时,显示订单(订单号、创建时间、手机信息、价格、数量、总价、支付方式、去付款或者去评价等)列表。组织数据并返回。写在goods子应用里面。
API: GET /orders/user/?page&page_size
参数:
通过请求头传递jwt token
响应:
{ "count": "数量", "next": "下一页", "previous": "上一页", "results": [ { "create_time": "订单创建时间", "order_id": "订单号", "total_amount": "商品总价", "pay_method": "支付方式", "status": "商品状态", "skus": [ { "count": "数量", "sku": { "default_image_url": "图片地址", "name": "商品名字" }, "price": "商品价格" } ], "freight": "运费" }, .... }
2.1业务逻辑
1.获取登录用户。
2.获取该用户的所有订单,根据创建时间进行排序。
3.将所有的商品信息进行嵌套序列化。(此处采用关联对象的嵌套序列化器来进行嵌套序列化)
4.返回给前端相对应的数据。
我们为了使用列表的分页效果,可以继承rest_framework.mixins中的ListModelMixin。这个模块为我们提供了list方法,进入源代码中进行查看,发现里面写了分页的逻辑。我们可以使用其指定的list方法。如果满足不了我们的需求,我们可以重写list方法,将其默认list方法中的分页逻辑代码粘贴过来即可。
3.微博登录
3.1获取微博登录网址
API: GET /oauth/weibo/authorization/?next=<登录之后的网址>
参数:
通过查询字符串传递登录之后访问页面地址
响应:
{
"login_url":"微博登录网址"
}
3.1.1业务逻辑
与之前QQ登录接口的逻辑完全相同。
1.通过查询字符串获取next。
2.组织微博登录网址和参数。
3.返回微博组织好的微博登录网址。
3.2获取微博登录用户的access_token
API: GET /oauth/sina/user/?code=<code>
参数:
通过查询字符串传递code
响应:
如果用户已经绑定,直接生成jwt token并返回
{ 'token': "jwt token", 'username': "用户名", 'user_id': "用户的id" }
如果用户未绑定过网站的用户,将access_token加密并返回
- 3.2.1业务逻辑
6. { 7. "access_token":"加密过的微博用户唯一凭证" 8. }
1.获取code并进行校验。(此处的code必须进行传递)。
2.获取微博用户的accesstoken(accesstoken是微博登录用户的唯一标示)。
3.如果没有绑定,将access_token加密进行返回,登录用户进入绑定页面,完成绑定。
4.如果已经绑定,我们可以直接生成jwt token返回给客户端,然后登录用户直接进入商城首页,不需要进入绑定页面。
3.3保存微博登录绑定数据
API: POST /oauth/sina/user/ 参数: { "mobile":"手机号", "password":"密码", "sms_code":"短信验证码", "access_token":"加密的微博用户唯一标识" } 响应: { "id":"用户id", "username":"用户名", "token":"jwt token" }
3.3.1业务逻辑
1.获取参数并进行校验(参数完整性,手机号格式是否正确,短信验证码是否正确,access_token是否有效)。
2.保存微博绑定的数据。
3.返回应答,绑定成功。
3.4生成图片验证码
API: GET /image_codes/(?P<image_code_id>\w{8}-\w{4}-\w{4}-\w{4}-\w{12})/ 参数: 通过url地址获取image_code_id 响应: { "image":"图片验证码", } # 需要指定"content_type"为"image/jpg",让浏览器按照图片格式对数据进行解析,否则浏览器默认按text格式对数据进行解析。
返回数据的时候,我们可以使用HttpResponse,它的效果与Flask中的make_responsex相同。
HttpResponse(image,content_type='image/jpg')
3.4.1业务逻辑
1.生成图片验证码。
2.将图片验证码保存到redis数据库中,设置有效期为300s。可以使用图片验证码的id为键,图片验证码内容为值的形式进行存储。
3.将图片验证码返回给前端页面,做出响应。
3.5发送短信验证码
之前我们设置过了发送短信验证码。为了添加图片验证码,使得短信验证码是在校验过图片验证码之后再发送,我们需要修改之前的发送短信验证码逻辑。
之前我们的注册登录和QQ绑定用户时没有图片验证码的校验,所以我们将添加的逻辑代码放到一个if语句判断中。前端发送图片验证码是通过get请求,以查询字符串的形式向后端传递图片验证码。如果有查询字符串,那么我们进行校验,如果没有查询字符串,那么我们不进行此次校验。
3.5.1业务逻辑
1.获取查询字符串中的图片验证码和验证码id。
2.从redis缓存中取出图片验证码内容。
3.如果取到了我们将redis缓存中的图片验证码删除,因为已经没用了,不必继续占用我们的空间。
4.如果没有取到,那么向前端传递错误信息,图片验证码失效。
5.进行图片验证码的校验,可以将用户输入的图片验证码全部转换成小写,然后与redis缓存中取到的验证码进行比较。
6。返回响应信息。
4.找回密码功能
4.1找回密码业务逻辑
1.输入账号(这里的账号既可以支持用户名又可以支持手机号),输入图片验证码。
2.后端获取用户账号进行身份认证。
3.发送短信验证码,完成身份的验证。
4填写两次新的密码,提交数据。
5.修改完成。
4.2第一步
API: GET /accounts/(?P<username>\w+)/sms/token/ 参数: 通过查询字符串传递image_code和image_code_id. 通过url传递username 响应: { "mobile":"手机号", "access_token":"通过身份认证的标识" }
4.2.1业务逻辑
1.输入账号和图片验证码,发送请求到后端,以 get 方式,参数拼接在链接后面;
2.后端对账号进行验证,调用之前的方法,可以同时判断手机号和账号名,查看有没有当前用户;
user =User.objects.get(username=username)
因为我们之前重写过Django的认证后端类,所以认证方法username既可以传账号,又可以传入手机号。
3.使用序列化器对图片验证码进行验证,取出 text 和图片对应 id,从redis中进行查询出真实的图片 text,判断 text 是否过期,对传过来的 text 和真实 text 进行对比,对比前需要进行转码和转小写,判断成功返回数据;
4.根据 user 对象的手机号生成 access_token;
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer tjs = TJWSSerializer(settings.SECRET_KEY, 300) access_token = tjs.dumps({'user': user.mobile}).decode()
5.将手机号的中间四位替换成 * 号,防止手机号直接暴露出去;返回给客户端的手机号就是带 *
号的数据,前端页面在进行下一步显示的时候,也是显示带星号的手机号。
不了解正则怎么用,使用最基础的字符串相关操作实现了这个功能。
per = user.mobile[0:3] back = user.mobile[-5:-1] sec = per + '****' + back
6.将修改过的手机号和生成的 token 返回给前端,token 中保存正确的手机号。
使用 itsdangerous 生成凭据 access_token,使用 TimedJSONWebSignatureSerializer 可以生成带有有效期的 token。
JWT 和 itsdangerous 生成的token区别是,JWT 生成的 token 用来保持登录状态使用,而 其他需要验证的 token 都使用由 itsdangerous 生成的
4.3第二步
API: GET /sms_codes/ 参数: 通过查询字符串获取access_token 响应: { "message":"OK" }
4.3.1业务逻辑
1.前端发送请求,带上上一步生成的 access_token;
2.在模型类中定义验证 token 的方法,使用 itdangerous 提供的方法进行反验证,取出存在token 中的手机号,进行判断是否在 60s 内,防止重复发送;
3.生成短信验证码,存入 redis,使用异步 celery 发送短信;
4.返回成功消息;
4.4第三步
API: GET /accounts/(?P<username>\w+)/password/token/ 参数: 通过url传递username, 通过查询字符串传递sms_code 响应: { “token”:“用于修改密码的token”, "user_id":"用户ID" }
4.4.1业务逻辑
1.用户收到短信并填写短信验证码;
2.发送请求到后端,带上 account 和 sms_code;
3.后端编写序列化器对参数进行校验;
4.生成用于修改密码的 token,将 userid 保存进去,返回 userid 和 token
4.5第四步
API: POST /users/(?P<pk>\d+)/password/ 参数: 通过url传递id,通过查询字符串传递token 响应: { "id":"用户id", "username":"用户名", "mobile":"手机号" }
4.5.1业务逻辑
进入到这一步,用户的身份已经被确认,进行密码的重置即可,为了防止被别人拿着 accesstoken 去对别人的用户进行设置,所以也需要对 userid 和 accesstoken 中保存的 userid 进行比较,确认了身份在进行修改。
1.在模型类中实现检验修改密码 token 的方法,取出 data,判断 user_id 是否一样;
2.定义重置密码序列化器,判断两次密码是否一样,判断是否是当前用户,返回数据;
3.调用 updata 方法更新密码;
4.返回重置密码成功信息。
5.评论功能
5.1获取订单评论页面
API: GET /orders/(?P<order_id>\d+)/uncommentgoods/
参数:
通过请求头传递jwt token
通过查询字符串传递order_id
响应:
- 5.1.1业务逻辑
1. { 2. "id":"订单id", 3. "sku":{ 4. "id":"商品id", 5. "name":"商品名称", 6. "default_image_url":"默认图片地址" 7. }, 8. "count":"商品数量", 9. "price":"商品价格" 10. }
1.根据order_id获取订单。
2.自定义序列化器类,添加我们需要的字段。
3.将数据序列化并返回。
5.2提交评论信息
API: POST /orders/(?P<order_id>\d+)/comments/ 参数: 通过请求头传递jwt token { "comment": "评论", "is_anonymous": "是否匿名评价", "order":"订单编号", "score":"满意度评价", "sku":"商品编号" } 响应: { "comment": "评论", "is_anonymous": "是否匿名评价", "score":"满意度评价", "sku":"商品编号" }
5.2.1业务逻辑
1.获取前端提交的评论信息。
2.保存数据到数据库。
3.将数据序列化并返回。
此步一定要确保上个接口提交给前端的数据正确,否则,这个接口获取不到完整的信息会一直失败。