不可不学系列(其二): Token认证机制让你的Web项目插入梦想的翅膀

Token认证机制

Token的优势

  • 可实现多种客户端的统一会话管理
  • 降低与其业务系统的耦合
  • 很容易加入第三方认证的支持

生成Token

服务器端 : 按规则生成token信息缓存在redis中, 同时返回给客户端

客户端: 请求登录成功保存token, 并附加在下次请求的http信息头中, 以供服务器验证

置换Token

设置定期刷新会话, 防止被恶意盗取

Token数据结构

客户端标识-USERCODE - USERID -CREATIONDATE-RONDEM(6位)

Token示例

  • TokenService
@Service
public class TokenServiceImpl  implements  TokenService{

    @Resource
    private RedisAPI redisAPI;

    /**
     * token: 客户端标识-USERCODE - USERID -CREATIONDATE-RONDEM(6位)
     * @param userAgent
     * @param admin
     * @return
     */
    @Override
    public String generateToken(String userAgent, WebAdmin admin) {
        StringBuilder sb = new StringBuilder();

        UserAgent agent = UserAgent.parseUserAgentString(userAgent);
        //移动设备
        if(agent.getOperatingSystem().isMobileDevice()) {
            sb.append("MOBILE-");
        } else
            sb.append("PC-");

        sb.append(MD5Util.getMD5(admin.getLoginCode(), 16)).append("-");
        sb.append(admin.getId().toString()).append("-");
        sb.append(new SimpleDateFormat("yyyyMMddHHmmsss").format(new Date())).append("-");
        sb.append(MD5Util.getMD5(userAgent, 6));
        return sb.toString();
    }


    /**
     * 需要针对不同的客户端 需要不同的过期处理
     * @param token
     * @param admin
     */
    @Override
    public void save(String token, WebAdmin admin) {
        if(token.startsWith("PC-")) {
            redisAPI.set(token,  JSONObject.toJSONString(admin), 2 * 60 * 60);
        } else {
            //移动端不需要过期
            redisAPI.set(token,  JSONObject.toJSONString(admin));
        }

    }
    
      @Override
    public boolean validate(String userAgent, String token) {
        if(!redisAPI.keyExist(token)) {
            return false;
        }

        String md5Agent = token.split("-")[4];
        //判断是不是同一个浏览器
        if(!md5Agent.equals(MD5Util.getMD5(userAgent, 6))) {
            return  false;
        }

        //不需要考虑过期时间 一方面如果是pc端过期 redis会直接清理 如果是移动端也不用考虑
        return  true;

    }
}

注: 需要引入1个依赖: 至于redis和MD5,你使用token肯定是引入了,这里就不赘述了

<dependency>
    <groupId>nl.bitwalker</groupId>
    <artifactId>UserAgentUtils</artifactId>
    <version>1.2.4</version>
</dependency>

验证Token

客户端: 将token附加到请求的header中

服务端: 从header取出token, 将其和redis中key-value进行比对

代码在validate方法中

删除Token

直接手动调用redis的del的方法即可

重置Token

这个场景是, 用户每次请求业务时,都应该校验其token的有效期, 如果约定时间有效(一般是半个小时) 那么你可以访问, 如果无效那么 我需要置换token 具体细节如下

 	//保护期30分钟
    private long protectedTime = 30 * 60 * 1000;
	//延迟
    private int delayTime = 2 * 60;
    @Override
    public String reload(String userAgent, String token) throws Exception {
        //1验证token是否有效
        if (!redisAPI.keyExist(token)) {
            throw  new Exception("token 无效!");
        }
        //2.是否到了置换时间
        String genDateStr = token.split("-")[3];
        Date genDate = new SimpleDateFormat("yyyyMMddHHmmsss").parse(genDateStr);
        //经过的时间
        long pass = Calendar.getInstance().getTimeInMillis() - genDate.getTime();
        //判断是否在保护期之内
        if(pass < protectedTime) {
            throw new Exception("token置换保护期, 无法置换! 剩余" + (protectedTime - pass ) / 1000);
        }

        //生成新的tokne
        WebAdmin admin = JSONObject.parseObject(redisAPI.get(token), WebAdmin.class);
        String newToken = generateToken(userAgent, admin);
        //3.老的token 延迟2分钟过期
        redisAPI.set(token,  redisAPI.get(token), delayTime);
        //4.新的token保存
        save(newToken, admin);
        return newToken;
    }

一般置换Token是放在定时任务中

说说心里话

最近又到了秋招的环节了, 笔者作为一名即将步入职场的新盆友, 正在疯狂吸收"全(栈)站"的知识, 虽然有些疲倦 但是每次掌握一个技能然后分享给大家这个阶段还是挺快乐的, 希望我的童鞋们多多捧场 让我更有信心更新下去, I need You!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值