Jwt攔截器和工具類


JWT json web token

Json web token (JWT), 是為了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標准( (RFC 7519).該token被設計為緊湊且安全的,特別適用於分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。

綜合了網上一些現有帖子寫了一個工具類和攔截器

工具類
 1 public class JWTUtil {
 2     //密匙
 3     private static final String TOKEN_SECRET = "privateKey";
 4 
 5     /**
 6      * 創建jwt
 7      * @param subject {id:100,name:xiaohong} 用戶id,用戶的name,用戶的pasword都可以
 8      * @param liveMillis 存活時間
 9      * @return jwt
10      */
11 
12     public static String setToken(String subject,
13                                   long liveMillis ){
14         //生成隨機的32位的jwtId
15         String jwtId= UUID.randomUUID().toString().replace("-", "").toUpperCase();
16         //指定簽名的時候使用的加密算法,就是header
17         SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
18         //設置簽證頒發時間
19         long nowMillis = System.currentTimeMillis();
20         Date now = new Date(nowMillis);
21         //創建payload的私有聲明
22         Map<String,Object> claims = new HashMap<String,Object>();
23         claims.put("uid", "DSSFAWDWADAS...");
24         claims.put("user_name", "admin");
25         claims.put("nick_name","DASDA121");
26         //創建JWT
27         JwtBuilder builder = Jwts.builder().setClaims(claims)
28                 //設置jwt的id
29                 .setId(jwtId)
30                 //設置簽證時間
31                 .setIssuedAt(now)
32                 //設置這個jwt的持有人,譬如加上持有人的id
33                 .setSubject(subject)
34                 //設置簽名算法以及密匙
35                 .signWith(signatureAlgorithm, TOKEN_SECRET);
36         //設置過期時間
37         if(liveMillis >= 0){
38             long endMillis = nowMillis + liveMillis;
39             Date end = new Date(endMillis);
40             builder.setExpiration(end);
41         }
42         return builder.compact();
43     }
44 
45     /**
46      * 解析jwt,變成你能驗證的樣子
47      * @param jwt
48      * @return
49      */
50     public static Claims parsJwt(String jwt){
51         Claims claims = null;
52         try {
53             claims = Jwts.parser()
54                     .setSigningKey(TOKEN_SECRET)
55                     .parseClaimsJws(jwt).getBody();
56         } catch (ExpiredJwtException e) {
57             System.out.println("Token已過期");
58         } catch (UnsupportedJwtException e) {
59             System.out.println("Token格式錯誤");
60         } catch (MalformedJwtException e) {
61             System.out.println("Token沒有被正確構造");
62         } catch (SignatureException e) {
63             System.out.println("簽名失敗");
64         } catch (IllegalArgumentException e) {
65             System.out.println("非法參數異常");
66         }
67         return claims;
68     }
69 
70     /**
71      *自定義想要驗證的東西,你存在subject里面的東西。
72      * @param token
73      * @return
74      */
75     public static Boolean isToken(String subject, String token){
76         //獲取解析后的屬性體
77         try {
78             Claims claims  = null;
79             claims = parsJwt(token);
80             //下面判斷這個token除了格式之外你想判斷的東西。測試自定義的subject為"{id:100,name:xiaohong}"
81             if( subject.equals(claims.getSubject())){
82                 return true;
83             }else{
84                 return false;
85             }
86         } catch (Exception e) {
87             return false;
88         }
89 
90     }
91 
92 }

 攔截器

 1 @Component
 2 public class JwtFilter implements HandlerInterceptor {
 3     private static String[] IGNORE_URL = {"/user/login"};
 4     private static Logger log = LoggerFactory.getLogger(JwtFilter.class);
 5     @Override
 6     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 7         System.out.println("-----------------開始進行地址攔截------------------------");
 8         String token = request.getHeader("token");
 9         String username = String.valueOf(GetRequestBody.get(request, "username"));
10         if(!"".equals(token) && token != null){
11             if(!JWTUtil.isToken(username, token)){
13                 return false;
14             }
15         }
16 
17         return true;
18     }
19     @Override
20     public  void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
21 
22     }
23     @Override
24     public  void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
25 
26     }
27 }

 

controller使用情況

 1 @RequestMapping("/user")
 2 public class UserController {
 3     private static final long TOKEN_LIVE = 15 * 60 * 1000;
 4     @Autowired
 5     private UserService userService;
 6     @Autowired
 7     private RedisUtil redisUtil;
 8 
 9     /**
10      * 返回兩個參數 0 ,1 1表示驗證通過,0 表示驗證失敗
11      * @param username
12      * @param password
13      * @param request
14      * @param response
15      * @return
16      */
17     @RequestMapping("/login")
18     public R login(String username , String password, HttpServletRequest request, HttpServletResponse response) throws IOException {
19         User user = null;
20         List<User> list = userService.sel(username, null);
21         if(list.size() == 0 || list.isEmpty()){
22             return R.ok("0");
23         }
24         System.out.println(request.getHeader("token"));
25         if(redisUtil.get(username) == null){
26             user = list.get(0);
27             System.out.println("數據庫查詢");
28             if(user != null && user.getPassword().equals(password)){
29                 redisUtil.set(username, user);
30                 redisUtil.expire(username, 15 * 60 * 1000);
31                 response.setHeader("token", JWTUtil.setToken(username, 5 * 1000));
32                 System.out.println(JWTUtil.setToken(username, 5 * 1000));
33                 return R.ok("1");
34             }else{
35                 return R.ok("0");
36             }
37         }else{
38             user = (User) redisUtil.get(username);
39             System.out.println("緩存查詢");
40             if(user != null && user.getPassword().equals(password)){
41                 return R.ok("1");
42             }else{
43                 return R.ok("0");
44             }
45         }
46     }
47 }

 

結合了緩存 來做,在這里也把緩存工具類放上

  1 import org.springframework.beans.factory.annotation.Autowired;
  2 import org.springframework.data.redis.core.RedisTemplate;
  3 import org.springframework.stereotype.Component;
  4 
  5 
  6 import java.util.List;
  7 import java.util.Map;
  8 import java.util.Set;
  9 import java.util.concurrent.TimeUnit;
 10 
 11 @Component
 12 public class RedisUtil {
 13     @Autowired
 14     private RedisTemplate redisTemplate;
 15     //===================================common==================================
 16 
 17     /**
 18      * 指定緩存過期時間
 19      * @param key 主鍵
 20      * @param time 過期時間 秒
 21      * @return
 22      */
 23     public boolean expire(String key, long time){
 24         try{
 25             if(time > 0){
 26                 redisTemplate.expire(key, time, TimeUnit.SECONDS);
 27             }
 28             return true;
 29         }catch(Exception e){
 30             e.printStackTrace();
 31             return false;
 32         }
 33     }
 34 
 35     /**
 36      * 獲取過期時間
 37      * @param key 主鍵
 38      * @return long時間
 39      */
 40     public long getExpire(String key){
 41         return redisTemplate.getExpire(key);
 42     }
 43 
 44     /**
 45      * 判斷key是否存在
 46      * @param key
 47      * @return
 48      */
 49     public boolean hasKey(String key){
 50         try{
 51             return redisTemplate.hasKey(key);
 52         }catch (Exception e){
 53             return false;
 54         }
 55     }
 56 //============================String======================================
 57 
 58     /**
 59      * 存入緩存
 60      * @param key
 61      * @param value
 62      * @return
 63      */
 64     public boolean set(String key, Object value){
 65         try{
 66             redisTemplate.opsForValue().set(key, value);
 67             return true;
 68         }catch(Exception e){
 69             e.printStackTrace();
 70             return false;
 71         }
 72     }
 73     /**
 74      * 刪除緩存
 75      * 未完成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 76      * @param key 主鍵可以單個或者集合
 77      */
 78     public void del(String... key){
 79         if(key.length > 0 && key != null){
 80             if(key.length == 1 ){
 81                 redisTemplate.delete(key);
 82             }else{
 83                 redisTemplate.delete(key);
 84             }
 85         }
 86     }
 87 
 88     /**
 89      * 獲取緩存
 90      * @param key
 91      * @return
 92      */
 93     public Object get(String key){
 94         return key == null ? null : redisTemplate.opsForValue().get(key);
 95     }
 96 
 97     /**
 98      * 自增
 99      * @param key 主鍵
100      * @param delta 增加多少(>0)
101      * @return
102      */
103     public long incr(String key, long delta){
104         if(delta < 0){
105             throw new RuntimeException("遞增因子必須大於零!");
106         }else{
107             return redisTemplate.opsForValue().increment(key, delta);
108         }
109     }
110 
111     /**
112      * 遞減
113      * @param key 主鍵
114      * @param delta 遞減多少(>0)
115      * @return
116      */
117     public long decr(String key, long delta){
118         if(delta < 0){
119             throw new RuntimeException("遞減因子必須大於零!");
120         }else{
121             return redisTemplate.opsForValue().decrement(key, -delta);
122         }
123     }
124 //==============================hash============================================
125 
126     /**
127      * HashGet
128      * @param key 鍵 不為 null
129      * @param item 項 不為 null
130      * @return
131      */
132     public Object hGet(String key, String item){
133         return redisTemplate.opsForHash().get(key, item);
134     }
135 
136     /**
137      * 獲取hashkey對應的所有key
138      * @param key
139      * @return
140      */
141     public Map<Object, Object> hmGet(String key){
142         return redisTemplate.opsForHash().entries(key);
143     }
144 
145     /**
146      * hashset
147      * @param key 鍵
148      * @param map 對應的多個鍵值
149      * @return
150      */
151     public boolean hSet(String key, Map<String, Object> map){
152         try{
153             redisTemplate.opsForHash().putAll(key, map);
154             return true;
155         }catch(Exception e){
156             e.printStackTrace();
157             return false;
158         }
159     }
160 
161     /**
162      * hashset,並設置過期時間
163      * @param key 鍵
164      * @param map 對應的多個鍵
165      * @param time 過期時間
166      * @return
167      */
168     public boolean hmSet(String key, Map<String, Object> map, long time){
169         try{
170             redisTemplate.opsForHash().putAll(key, map);
171             if(time > 0){
172                 expire(key, time);
173             }
174             return true;
175         }catch(Exception e){
176             e.printStackTrace();
177             return false;
178         }
179     }
180 
181     /**
182      * 向緩存hash表中插入數據,如果表不存在則創建這個表
183      * @param key 鍵
184      * @param item map 鍵
185      * @param value map值
186      * @return
187      */
188     public boolean hSet(String key, String item, Object value){
189         try{
190             redisTemplate.opsForHash().put(key, item, value);
191             return true;
192         }catch(Exception e){
193             e.printStackTrace();
194             return false;
195         }
196     }
197 
198     /**
199      * 向緩存中的map存入數據,如果map不存在則創建這個表,同時設置過期時間
200      * @param key 鍵
201      * @param item map鍵
202      * @param value value
203      * @param time 過期時間,如果這個map已經有過期時間,則會重置這個過期時間
204      * @return
205      */
206     public boolean hSet(String key, String item, Object value, long time){
207         try{
208             redisTemplate.opsForHash().put(key, item, value);
209             if(time > 0){
210                 expire(key, time);
211             }
212             return true;
213         }catch(Exception e){
214             e.printStackTrace();
215             return false;
216         }
217     }
218 
219     /**
220      * hash刪除數據
221      * @param key 鍵 不為null
222      * @param values 值 不為null
223      */
224     public void hDel(String key, Object... values){
225         redisTemplate.opsForHash().delete(key, values);
226     }
227 
228     /**
229      *判斷是否含有某個鍵
230      * @param key 不為null
231      * @param item 不為null
232      * @return
233      */
234     public boolean hHasKey(String key, String item){
235         return redisTemplate.opsForHash().hasKey(key, item);
236     }
237 
238     /**
239      * hash遞增,如果不存在則創建,並把新增的值返回
240      * @param key 鍵
241      * @param item map鍵
242      * @param by 增加多少(>0)
243      * @return
244      */
245     public double hIncr(String key, String item, double by){
246         return redisTemplate.opsForHash().increment(key, item, by);
247     }
248 
249     /**
250      * hash遞減不存在就創建,並把新增的值返回
251      * @param key 鍵
252      * @param item map鍵
253      * @param by 遞減因子(>0)
254      * @return
255      */
256     public double hDecr(String key, String item, double by){
257         return redisTemplate.opsForHash().increment(key, item, -by);
258     }
259 //================================set=====================================
260 
261     /**
262      * 獲取key的所有set
263      * @param key
264      * @return
265      */
266     public Set<Object> sGet(String key){
267         try{
268             return redisTemplate.opsForSet().members(key);
269         }catch(Exception e){
270             e.printStackTrace();
271             return null;
272         }
273     }
274 
275     /**
276      * 判斷key值是否含有value
277      * @param key
278      * @param value
279      * @return
280      */
281     public boolean sHasKey(String key, Object value){
282         try{
283             return redisTemplate.opsForSet().isMember(key, value);
284         }catch(Exception e){
285             e.printStackTrace();
286             return false;
287         }
288     }
289 
290     /**
291      *將數據存入set緩存中
292      * @param key 鍵
293      * @param values 值
294      * @return 成功個數
295      */
296     public long sSet(String key, Object... values){
297         try{
298             return redisTemplate.opsForSet().add(key, values);
299         }catch(Exception e){
300             e.printStackTrace();
301             return 0;
302         }
303     }
304 
305     /**
306      * 向緩存中添加數據,並設置過期時間,如果已經設置過期時間則重置
307      * @param key 鍵
308      * @param time 過期時間
309      * @param values 值
310      * @return 成功個數
311      */
312     public long sSetAndTime(String key, long time, Object... values){
313         try{
314             long count = redisTemplate.opsForSet().add(key,values);
315             if(time > 0){
316                 expire(key, time);
317             }
318             return count;
319         }catch(Exception e){
320             e.printStackTrace();
321             return 0;
322         }
323     }
324 
325     /**
326      * 獲取set的長度
327      * @param key
328      * @return
329      */
330     public long sGetSetSize(String key){
331         try{
332             return redisTemplate.opsForSet().size(key);
333         }catch(Exception e){
334             e.printStackTrace();
335             return 0;
336         }
337     }
338 
339     /**
340      * 移除值為value的
341      * @param key 鍵
342      * @param values 值 可以是多個
343      * @return 移除的個數
344      */
345     public long sRemove(String key, Object... values){
346         try{
347             long count = redisTemplate.opsForSet().remove(key, values);
348             return count;
349         }catch(Exception e){
350             e.printStackTrace();
351             return 0;
352         }
353     }
354     //=====================list===============================
355 
356     /**
357      * 獲取list緩存
358      * @param key 鍵
359      * @param start 開始
360      * @param end 結束 0 到 -1 所有值
361      * @return
362      */
363     public List<Object> lGet(String key, long start, long end){
364         try{
365             return redisTemplate.opsForList().range(key, start, end);
366         }catch(Exception e){
367             e.printStackTrace();
368             return null;
369         }
370     }
371 
372     /**
373      * 獲取list的長度
374      * @param key 鍵
375      * @return list長度
376      */
377     public long lGetListSize(String key){
378         try{
379             return redisTemplate.opsForList().size(key);
380         }catch(Exception e){
381             e.printStackTrace();
382             return 0;
383         }
384     }
385 
386     /**
387      * 通過index索引來獲取value
388      * @param key 鍵
389      * @param index index 0 是第一個元素,-1是最后一個元素,-2是倒數第二個元素
390      * @return
391      */
392     public Object lGetIndex(String key, long index){
393         try{
394             return redisTemplate.opsForList().index(key, index);
395         }catch(Exception e){
396             e.printStackTrace();
397             return null;
398         }
399     }
400 
401     /**
402      * 向list中插入數據
403      * @param key 鍵
404      * @param value 值
405      * @return
406      */
407     public boolean lSet(String key, Object value){
408         try{
409            redisTemplate.opsForList().rightPush(key, value);
410            return true;
411         }catch(Exception e){
412             e.printStackTrace();
413             return false;
414         }
415     }
416 
417     /**
418      * 向list中插入value
419      * @param key 鍵
420      * @param value 值
421      * @param time 過期時間
422      * @return
423      */
424     public boolean lSetAndTime(String key, Object value, long time){
425         try{
426             redisTemplate.opsForList().rightPush(key, value);
427             if(time > 0){
428                 expire(key, time);
429             }
430             return true;
431         }catch(Exception e){
432             e.printStackTrace();
433             return false;
434         }
435     }
436 
437     /**
438      * 重寫方法,設置list
439      * @param key
440      * @param list
441      * @return
442      */
443     public boolean lSet(String key, List<Object> list){
444         try{
445            redisTemplate.opsForList().rightPush(key, list);
446            return true;
447         }catch(Exception e){
448             e.printStackTrace();
449             return false;
450         }
451     }
452 
453     /**
454      * 插入list並設置過期時間
455      * @param key 鍵
456      * @param list value
457      * @param time 過期時間
458      * @return
459      */
460     public boolean lSetAndTime(String key, List<Object> list, long time){
461         try{
462             redisTemplate.opsForList().rightPush(key,list);
463             if(time > 0){
464                 expire(key, time);
465             }
466             return true;
467         }catch(Exception e){
468             e.printStackTrace();
469             return false;
470         }
471     }
472 
473     /**
474      * 更新數據
475      * @param key
476      * @param index
477      * @param value
478      * @return
479      */
480     public boolean lUpdateIndex(String key, long index, Object value){
481         try{
482             redisTemplate.opsForList().set(key, index, value);
483             return true;
484         }catch(Exception e){
485             e.printStackTrace();
486             return false;
487         }
488     }
489 
490     /**
491      * 移除count個值是value的
492      * @param key 鍵
493      * @param count 移除數量
494      * @param value 值
495      * @return
496      */
497     public long lRemove(String key, long count, Object value){
498         try{
499             long num = redisTemplate.opsForList().remove(key, count, value);
500             return num;
501         }catch(Exception e){
502             e.printStackTrace();
503             return 0;
504         }
505     }
506 }
View Code

 

 遇到的問題

1.上手是邏輯混亂,不知道token的頒發和判斷在哪里發生

后來確定 controller負責token的頒發,攔截器來判斷token是否合法和過期情況。

2.我把user.username屬性作為判斷token構造的一個屬性,但是我不知道怎么在request的body中獲取這個username屬性

對此我直接封裝了一個方法,把request和你想要的屬性當作參數傳入,然后獲取參數的屬性。

 1 import javax.servlet.http.HttpServletRequest;
 2 import java.util.Enumeration;
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 public class GetRequestBody {
 7     public static Object get(HttpServletRequest request, String string) {
 8         Map<String,Object> map = new HashMap<String,Object>();
 9         Enumeration paramNames = request.getParameterNames();
10         while (paramNames.hasMoreElements()) {
11             String paramName = (String) paramNames.nextElement();
12 
13             String[] paramValues = request.getParameterValues(paramName);
14             if (paramValues.length >0) {
15                 String paramValue = paramValues[0];
16                 if (paramValue.length() != 0) {
17                     map.put(paramName, paramValue);
18                 }
19             }
20         }
21         return map.get(string);
22 
23     }
24 
25 }

 

 3.我認為user第一次驗證的時候token都為空,所以當token為空的時候我選擇了直接放行,但是總覺得不是這么回事,所以我覺得這是一個很大的問題。我在想要不要定義一個統一的默認token當user第一次來的時候帶着這個token來進行判斷。

但是前端token的拼裝我並不了解,也不擅長所以就耽擱了。

 

 

 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM