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

Token认证机制

Token的优势

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

生成Token

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

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

置换Token

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

Token数据结构

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

Token示例

  • TokenService
@Service
public class TokenServiceImpl  implements  TokenService{
<span class="token annotation punctuation">@Resource</span>
<span class="token keyword">private</span> RedisAPI redisAPI<span class="token punctuation">;</span>

<span class="token comment">/**
 * token: 客户端标识-USERCODE - USERID -CREATIONDATE-RONDEM(6位)
 * @param userAgent
 * @param admin
 * @return
 */</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> String <span class="token function">generateToken</span><span class="token punctuation">(</span>String userAgent<span class="token punctuation">,</span> WebAdmin admin<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    StringBuilder sb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    UserAgent agent <span class="token operator">=</span> UserAgent<span class="token punctuation">.</span><span class="token function">parseUserAgentString</span><span class="token punctuation">(</span>userAgent<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//移动设备</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>agent<span class="token punctuation">.</span><span class="token function">getOperatingSystem</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isMobileDevice</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"MOBILE-"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span>
        sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"PC-"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>MD5Util<span class="token punctuation">.</span><span class="token function">getMD5</span><span class="token punctuation">(</span>admin<span class="token punctuation">.</span><span class="token function">getLoginCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"-"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>admin<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"-"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SimpleDateFormat</span><span class="token punctuation">(</span><span class="token string">"yyyyMMddHHmmsss"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"-"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>MD5Util<span class="token punctuation">.</span><span class="token function">getMD5</span><span class="token punctuation">(</span>userAgent<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> sb<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token comment">/**
 * 需要针对不同的客户端 需要不同的过期处理
 * @param token
 * @param admin
 */</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">save</span><span class="token punctuation">(</span>String token<span class="token punctuation">,</span> WebAdmin admin<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"PC-"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        redisAPI<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span>  JSONObject<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>admin<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">2</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
        <span class="token comment">//移动端不需要过期</span>
        redisAPI<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span>  JSONObject<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>admin<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>

  <span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">validate</span><span class="token punctuation">(</span>String userAgent<span class="token punctuation">,</span> String token<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>redisAPI<span class="token punctuation">.</span><span class="token function">keyExist</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    String md5Agent <span class="token operator">=</span> token<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"-"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token comment">//判断是不是同一个浏览器</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>md5Agent<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>MD5Util<span class="token punctuation">.</span><span class="token function">getMD5</span><span class="token punctuation">(</span>userAgent<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">return</span>  <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//不需要考虑过期时间 一方面如果是pc端过期 redis会直接清理 如果是移动端也不用考虑</span>
    <span class="token keyword">return</span>  <span class="token boolean">true</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

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

<dependency>
    <groupId>nl.bitwalker</groupId>
    <artifactId>UserAgentUtils</artifactId>
    <version>1.2.4</version>
</dependency>
  
  
  • 1
  • 2
  • 3
  • 4

验证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);
        }
    <span class="token comment">//生成新的tokne</span>
    WebAdmin admin <span class="token operator">=</span> JSONObject<span class="token punctuation">.</span><span class="token function">parseObject</span><span class="token punctuation">(</span>redisAPI<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">,</span> WebAdmin<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    String newToken <span class="token operator">=</span> <span class="token function">generateToken</span><span class="token punctuation">(</span>userAgent<span class="token punctuation">,</span> admin<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//3.老的token 延迟2分钟过期</span>
    redisAPI<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span>  redisAPI<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">,</span> delayTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//4.新的token保存</span>
    <span class="token function">save</span><span class="token punctuation">(</span>newToken<span class="token punctuation">,</span> admin<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> newToken<span class="token punctuation">;</span>
<span class="token punctuation">}</span><div class="hljs-button {2}" data-title="复制" data-report-click="{&quot;spm&quot;:&quot;1001.2101.3001.4259&quot;}"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li></ul></pre> 

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

说说心里话

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值