Token 简介

1.Token简介

  1. Token的引入:

    当项目要求进行前后端分离或移动端开发时,是无法使用 Session 的,那么需要使用 Token 进行 session 的管理,通过搭建一个认证(Auth)系统负责用户身份验证,并进行整个系统 Token 的维护与管理

  2. Token的定义:

    Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

  3. 使用Token的目的:

    Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。

2.Token的数据结构及内容

  1. Key:token

    其设计原则:必须保证在整个系统中唯一存在 根据不同客户端(PC、移动),为了便于统一管理和维护,token生成算法设计如下:

    1. PC 端:token:PC-USERCODE[加密]-USERID-CREATIONDATE-RONDEM[6 位]
    2. 移动端:token: MOBILE-USERCODE[加密]-USERID-CREATIONDATE-RONDEM[6 位]
  2. Value:存储登录用户的信息数据(数据格式为 json)

    具体内容包括:ID,账号,用户名,密码,用户类型,平台ID等

3.Token 有效期的维护

基于系统的安全性考虑,需要设置 Token 的有效期,并且为了维护 Token 的有效期,须把 Token 放入到 Redis 里进行维护管理。对于不同客户端(PC 端、移动端)的 Token 所设置的有效期策略不同:

  1. PC端

    Token 的有效期为 2 个小时,若 2 个小时内没有进行 Token 置换的话,就会自动在 Redis 里清除该 Token,那么当该用户再次发送请求时,则会提示:Token 失效,请重登录。此处应注意:前端须自行管理 Token 的生命周期,原因是 Token 存在 cookie 里,web的安全性较差。

  2. 移动端

    Token 永不失效,修改密码后须更换 Token。 注意:由于移动端的 Token 一般不需要过期,只有当在 PC 页面进行个人密码修改后,移动端才会退出重登录,或者当在移动端修改密码操作,用户也不需要退出重登录,直接在 Redis 中更新该 Token 中用户修改的新密码即可。

4.AS 系统(Auth System)

该系统主要负责登录用户身份的验证,登录成功后生成唯一的 Token,并将 Token 存入到 Redis 里进行维护管理,以及 Token 的置换(Reload)等

生成Token

当用户进行系统登录时,Auth 系统会进行用户名和密码的校验,验证成功后生成 Token,存入到 Redis 中,同时将该 Token 的 key 返回给前端,前端调用的所有 API 都必须传递该 Token,并规定 Token 统一放在请求头(header)里,后端需要获取当前用户信息时,就可以直接从 header 中获取即可。 为了保证绝对的安全,正常业务下的 API 返回给前端的 Token 信息如下:

{ 
 "status":"200", 
 "data":{ 
   "token":"token:PC-3066014fa0b10792e4a762-23-20170531133947-4f6496", 
   "ticket":"yhe736dyfhfyw", 
   "expTime":"6474783", 
   "genTime":"7565746" 
}, 
 "errorcode":"0", 
 "msg":{} 
} 

通常情况下返回给前端的 Token 数据只有四项内容:token(key)、ticket、Token 的生成时间、Token 的失效时间。为了安全考虑,不会包含当前用户的任何信息,每次后端需要获取Token 信息时,应从 header 中获取到 token(key)和 ticket,通过它们两个去 Redis 中进行 k-v 匹配获取相应的 Token 信息,即:当前用户的相关信息。

Token 置换

Token 置换规则定义:前端获取 Token 的 1.5 时后可进行 Token 置换,若在最后的半个小时内,客户端发出请求,则会进行 Token 置换,拿到重新生成的 Token(包括:token(key)、生成时间、失效时间),若客户端在最后的半个小时内没有发送任何请求,那么两个小时后自动过期,即:该 Token 自动从 Redis 里清除,用户须重新登录。

注意事项:

  1. 不论是最后半个小时的置换时间还是 Token 的 2 个小时有效期,都是根据系统的业务需求所设计的策略方案。
  2. 为了防止客户端恶意的进行 Token 置换,需要保证生成 Token 后的 1 个小时内不允许置换。
  3. 需要保证客户端传递有效的 Token 进行置换。
  4. 为了解决页面的并发问题,在进行置换 Token 时,生成新 Token,但是旧 Token 不能立即失效,应设置为置换后的时间延长 2 分钟。否则会出现页面因为 Token 失效而无法完成置换。

编写token置换模块

  1. 在exception文件夹下,创建TokenValidationFailedException,编写构造方法
public TokenValidationFailedException(String msg) {
     super(msg);
 }
  1. 理清置换token编写思路:

  2. 首先判断token是否有效

  3. 生成token后的一个小时内不允许置换

  4. 置换token,需要生成一个新的token,并且旧token不能立即失效,应设置为置换后时间延长两分钟

  5. 兼容手机端和pc端

  6. 在TokenService中添加旧token延迟时间

/**
  * 旧token延迟时间
  */
 public final static int REPLACEMENT_DELAY = 2*60;
  1. 在TokenService中编写token置换方法
/**
  * 置换token
  * 1,首先判断token是否有效
  * 2,生成token后的一个小时内不允许置换
  * 3,置换token,需要生成一个新的token,并且旧token不能立即失效,应设置为置换后时间延长两分钟
  * 4,兼容手机端和pc端
  */

//引入logger
private static Logger logger = Logger.getLogger(ItripUserServiceImpl.class);
 @Override
 public String replaceToken(String agent, String token) throws TokenValidationFailedException {
     //1,首先判断token是否有效
     if (!exists(token)){
         //终止置换
         throw new TokenValidationFailedException("未知的Token或Token已过期");
     }
     Date tokenGenTime;//生成时间
     try{
         //2,生成token后的一个小时内不允许置换
         String[] tokenDetails = token.split("-");
         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
         tokenGenTime = format.parse(tokenDetails[3]);
     } catch (ParseException e) {
         e.printStackTrace();
         logger.error(e);
         throw new TokenValidationFailedException("token格式错误"+token);
     }
     long passed = Calendar.getInstance().getTimeInMillis()-tokenGenTime.getTime();
     if (passed < REPLACEMENT_PROTECTION_TIMEOUT * 1000){
         throw new TokenValidationFailedException("token处于置换保护时间,剩余"+
                 (REPLACEMENT_PROTECTION_TIMEOUT)*1000+"(s),禁止置换");
     }
//        3,置换token,需要生成一个新的token,并且旧token不能立即失效,应设置为置换后时间延长两分钟
     String newToken = "";
     ItripUser itripUser = this.load(token);
     long ttl = redisAPI.ttl(token);//token有效时期
     //4,兼容手机端和pc端
     if (ttl > 0 || ttl == -1){
         newToken = this.generateToken(agent,itripUser);
         this.save(newToken,itripUser);
         redisAPI.set(token,REPLACEMENT_DELAY,JSON.toJSONString(itripUser));
     }else {
         throw new TokenValidationFailedException("当前token的过期时间异常,禁止置换");
     }
     return newToken;
 }
  1. 添加TokenController,引入tokenService,并编写置换token方法retoken
@Autowired
 private TokenService tokenService;

 @RequestMapping(value = "/retoken",method = RequestMethod.POST,produces = "application/json")
 @ResponseBody
 public Dto retoken(HttpServletRequest request){
     String agent = request.getHeader("user-agent");
     String token = request.getHeader("token");
     try {
         String newToken = tokenService.replaceToken(agent, token);
         ItripTokenVo itripTokenVo = new ItripTokenVo(Calendar.getInstance().getTimeInMillis()+ TokenService.SESSION_TIMEOUT*1000,
                 Calendar.getInstance().getTimeInMillis(),newToken);
         return DtoUtil.returnDataSuccess(itripTokenVo);
     } catch (Exception e) {
         e.printStackTrace();
         return DtoUtil.returnFail(e.getMessage(), ErrorCode.AUTH_AUTHENTICATION_FAILED);
     }
 }
  1. 启动tomcat,登录爱旅行,在redis中会有当前用户的token,使用postman可以测试,如测试结果msg返回‘token处于置换保护时间,剩余3600000(s),禁止置换’,则正常

5.前/后端具体实现

后端

Auth 系统需要提供 API :

  1. 生成 Token

    该接口返回的数据内容包括:Token 的 key(注:需要对敏感信息进行加密处理)、 Token 的生成时间、Token 的失效时间(注:过期时间减去生成时间一定是两个小时)

  2. Token 置换

    该接口返回新 Token。实现过程中需要注意如下几点:

    生成 Token 后的 1 个小时内不允许置换(注:主要是为了防止客户端恶意的进行 Token 置换)

    由于需要保证客户端传递的置换 Token 为真实存在并有效的,故需要在该API 方法内首先判断 Token 是否有效。

    在进行置换 Token,生成新 Token,旧 Token 不能立即失效,应设置为置换后的时间延长 2 分钟。

前端

  1. 登录成功后,接收 Token 放入 cookie 中,请求的时候从 cookie 中取出放入到 header 里,如下:

    $.ajax({ 
        headers:{ 
    		Accept:"application/json;charset=utf-8", 
    		Content-Type:"application/json;charset=utf-8",  
    		//从 cookie 中获取 
    		token:"token:PC-3066014fa0b10792e4a762-23-20170531133947-4f6496"  
    	}, 
    	type:"post", 
    	..... 
    }) 
    
    
  2. 负责服务器时间同步(根据 API 返回的 Token 生成时间、失效时间进行同步)

  3. 置换 Token 需要同步处理,即:保证只有一个请求置换 Token

### SA-Token 使用方法及常见问题 #### 一、SA-Token简介 SA-Token是一款轻量级Java权限认证框架,具有简洁易用的特点。该框架能够很好地与Spring Boot集成,并提供一系列强大而灵活的功能[^1]。 #### 二、主要特性概述 - **角色和权限认证**:支持基于角色的访问控制(RBAC),允许开发者定义不同级别的用户权限。 - **会话管理**:内置完善的在线用户管理体系,可轻松实现踢人下线等功能;默认采用内存方式保存token数据,在分布式场景下推荐使用Redis作为存储媒介[^2]。 - **优雅的设计理念**:相较于其他同类产品如Apache Shiro或Spring Security而言更为直观便捷,具备良好的扩展性和兼容性[^3]。 #### 三、基本操作指南 对于初次接触此工具的朋友来说,掌握以下几个方面尤为重要: ##### 登录流程演示 当构建一个Web应用程序时,创建安全可靠的登录机制至关重要。下面给出一段简化版代码片段用于说明如何利用`StpUtil.login()`完成账户身份验证过程[^4]: ```java @RestController @RequestMapping("/user") public class UserController { @PostMapping("/login") public SaResult login(@RequestParam String username, @RequestParam String password) { // 此处省略实际业务逻辑,即连接数据库校验用户名密码正确性的部分 // 若匹配成功,则调用如下语句记录此次登陆事件 StpUtil.login(userId); return SaResult.ok("Login succeeded."); } } ``` #### 四、常见疑问解答 针对使用者可能会遇到的一些典型困惑作出回应: - 如何解决跨域资源共享(CORS)? 可以考虑引入第三方库cors-filter或者直接配置web.xml文件中的filter映射规则来放宽浏览器同源策略限制。 - 怎样设置自定义异常处理器? 推荐继承BaseExceptionResolver类重写doResolve()函数来自定义全局错误页面样式以及返回码含义解释等内容。 - 是否存在官方文档可供查阅学习资料? 官方网站提供了详尽的手册文档和技术博客文章供参考阅读,建议定期关注更新动态以便及时获取最新资讯和支持服务。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值