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="{"spm":"1001.2101.3001.4259"}"></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!