Token+swagger记得推 分布式

enable能 使

1.Swagger简介

Swagger:类似于在线的javaDoc,直接运行,在线测试API 他是前后端联调的工具

API 应用程序的接口

1.1 Spring集成Swagger

两种------springfox-swagger2 swagger-springmvc 这里的示例 第一种

往接口上写注解(接口是controller里面提供的那些接口)

1.2 常用注解

(1)@Api 用在请求的上 表示对类的说明

示例:
 @Api(tags = "注册控制器")
@RestController
@RequestMapping("/api")
public class RegisterController {

结果显示:/swagger-ui.html必须要写

登录态应该存在数据库还是redis里_用户信息


(2)@ApiOperation:用在请求的方法上,说明方法的用途、作用

常用参数:

  • value=“说明方法的用途、作用”
  • notes="方法的备注说明"就是详细信息
  • httpMethod 指定HTTP方法,“GET”, “HEAD”, “POST”, “PUT”, “DELETE”, “OPTIONS” and “PATCH”
  • produces 设置MIME类型列表(output),例:“application/json, application/xml”,默认为空
  • protocols 设置特定协议,例:http, https, ws, wss。

(3)@ApiImplicitParams:用在请求的方法上,表示一组参数说明

单数是写在复数里面的

  • @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面

方法的参数如果为对象:

(4)@ApiModel:用于响应类上,表示一个返回响应数据的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)

  • @ApiModelProperty:用在属性上,描述响应类的属性
    value 此属性的简要说明。

登录态应该存在数据库还是redis里_第三方登录_02


登录态应该存在数据库还是redis里_用户信息_03


结果显示:

登录态应该存在数据库还是redis里_服务器_04


登录态应该存在数据库还是redis里_第三方登录_05


(5)

@ApiIgnore: 用在请求方法上,用于忽略对应方法,一般用于内部接口 生成的doc文档里面不显示此接口

<!--静态资源的放行-->

<mvc:default-servlet-handler></mvc:default-servlet-handler>

在线测试

登录态应该存在数据库还是redis里_服务器_06

最后访问的时候

2. Token技术分析

分布式开发

考虑登录session问题

考虑第三方登录的问题

登录态应该存在数据库还是redis里_服务器_07

2.1 分布式下的用户登录技术难点:

1.前端和后端分离(后端也是多模块部署),Session信息无法共享
2.前端可能是移动端App,无法使用Session

1.登录用户的来源(情况)
自注册用户
第三方登录的用户
内部注册(第一次使用第三方 随机帐号和密码等信息)

2.分析传统的登录实现
前端:填写帐号和密码
后端:接收帐号和密码
验证帐号和密码是否存在且正确
失败:
跳转回登录页面
提示用户名或密码错误!
成功:
将用户的部分帐号信息存储到Session作用域(一个用户来访问正好对应一次会话)
跳转到项目主页

3.分析分布式情况的登录实现
自注册用户:
前端:填写帐号(手机号)和密码
后端(auth):接收帐号和密码
验证帐号和密码是否存在且正确
失败:(DTO)
返回提示,用户名或密码错误!
成功:
【存储用户的部分帐号信息】

第三方登录用户:
前端:用户点击对应的第三方登录图标
后端(auth):接收用户到底要使用何种第三方登录方式
…(学习如何接入第三方 验证信息)
失败:
返回提示,第三方登录失败!
成功:
检查当前用户是否存在
存在:
【接入自注册用户的成功部分业务实现】
不存在:
进行第三方登录用户的注册(随机帐号、密码等信息)
【接入自注册用户的成功部分业务实现】

3.使用Token来模拟实现Session机制

【原版Session的大致流程】原版的Session不仅仅用于登录后用户信息的存储
1.浏览器访问项目服务器
2.服务器接收到此次访问之后,验证当前浏览器是否携带了指定的cookie信息(JSessionId)
没有携带:(第一次访问/Session已经过期)
会根据浏览器等信息来生成一个唯一的会话标识(JSessionId),并且会为其准备一块区域用于存储信息
在响应的同时,服务器会将此标识通过cookie响应到浏览器(默认的cookie是会话级,浏览器关闭即cookie销毁)
携带:
服务器开放浏览器访问对应Session区域的权限

【Token模拟实现Session】模拟的Session(Token)仅仅是用于登录后用户信息的存储

浏览器也可以实现携带类似的JsessionId(请求头 request header)
浏览器也可以在本地缓存(接收)服务器响应回来的类似的JsessionId(Cookie存储)

【JSessionId:】通过算法生成
token 生成算法设计如下:
	例如:PC端:PC-121adv212das-1-201908281128-123456
	PC 端: token:PC-USERCODE[加密]-USERID-CREATIONDATE-RANDEM[6位]
	移 动 端 : token:MOBILE-USERCODE[加密]-USERID-CREATIONDATE-RANDEM[6位]
【Session在服务器的存储区域:】通过Redis实现

redis和服务器独立 session是服务器里面的 redis是服务器外面的 他们之间是独立的

Redis中存储键值对
键:token:PC-121adv212das-1-201908281128-123456
值:用户的部分帐号信息
【过期时间:】(因为是仅仅存储登录后的用户信息,所以为了更好的体验,我们不采用Session的销毁机制)

Session默认过期时间为:30分钟(用户无操作)
Session在浏览器关闭之后会进行销毁(会话级Cookie消失了)

Redis可以设置键的存活时间
PC端:set(“token:PC-121adv212das-1-201908281128-123456”,【2小时】,用户的部分帐号信息)
用户如果一直在操作是不能进行销毁的:
我们通过前端的【置换请求】(前端自行判断,在还剩5分钟过期的时候还在操作)来界定用户是否还在操作。
前端通过服务器最初响应的Token的信息来界定:
Token的ID
Token的生成时间 2019.8.28 11:43
Token的过期时间 2019.8.28 13:43(未来前端 通过当前时间来和过期时间进行计算)

为了保证Token的安全性,我们在快要过期时,接收到了前端的【用户置换】请求,进行Token信息置换
置换成功之后将信息重新响应给客户端。

假设:
前端用户还有30分钟过期

,用户开始进行酒店预定。(前端1.5小时之后可以置换)
预定酒店请求 -> 携带着老Token信息 访问后端
为了防止出现请求并发时 老Token失效问题 将老Token额外存储2分钟
置换Token请求 -> 携带着老Token信息 访问后端 -> 响应新的Token(Redis也换了Token信息)
新的请求 -> 携带着新Token信息 访问后端

移动端:set(“token:MOBILE-121adv212das-1-201908281128-123456”,【“永久”】,用户的部分帐号信息)

为了简化开发,省略了【secrect key/ticket秘钥】

用户退出功能 就是把redis里面的token信息进行删除

生成Token的时候 可以通过User-Agent判断是客户端还是服务器端

登录态应该存在数据库还是redis里_用户信息_08

//@RequestHeader获取请求头信息
    @RequestMapping(value="/dologin",method= RequestMethod.POST)
    public Dto doLogin(@RequestParam String name, @RequestParam String password, @RequestHeader("user-Agent") String userAgent){
String userTokenJson = JSON.toJSONString(itripUserTokenVO);
        //json作用 对象封装成字符串
//存储部分用户信息

        ItripUserTokenVO itripUserTokenVO=new ItripUserTokenVO();
        //把itripUserTokenVo里面的信息赋值到itripUser中
        BeanUtils.copyProperties(itripUser,itripUserTokenVO);