支持跨域訪問: Cookie是不容許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸的用戶認證信息通
過HTTP頭傳輸.
無狀態(也稱:服務端可擴展行):Token機制在服務端不須要存儲session信息,由於Token 自身包含了全部登
錄用戶的信息,只須要在客戶端的cookie或本地介質存儲狀態信息.
更適用CDN: 能夠經過內容分發網絡請求你服務端的全部資料(如:javascript,HTML,圖片等),而你的服
務端只要提供API便可.
去耦: 不須要綁定到一個特定的身份驗證方案。Token能夠在任何地方生成,只要在你的API被調用的時候,你
能夠進行Token生成調用便可.
更適用於移動應用: 當你的客戶端是一個原平生臺(iOS, Android,Windows 8等)時,Cookie是不被支持的
(你須要經過Cookie容器進行處理),這時採用Token認證機制就會簡單得多。
CSRF:由於再也不依賴於Cookie,因此你就不須要考慮對CSRF(跨站請求僞造)的防範。
性能: 一次網絡往返時間(經過數據庫查詢session信息)總比作一次HMACSHA256計算 的Token驗證和解析
要費時得多.
不須要爲登陸頁面作特殊處理: 若是你使用Protractor 作功能測試的時候,再也不須要爲登陸頁面作特殊處理.
基於標準化:你的API能夠採用標準化的 JSON Web Token (JWT). 這個標準已經存在多個後端庫(.NET, Ruby,
Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)javascript
(1)建立maven工程,引入依賴前端
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
(2)使用工具類JwtUtilsjava
1 /** 2 * @author: Mr.Yang 3 * @create: 2020-02-13 21:19 4 **/ 5 @Getter 6 @Setter 7 @ConfigurationProperties("jwt.config") 8 public class JwtUtils { 9 //簽名私鑰 10 private String key; 11 //簽名失效時間 12 private Long failureTime; 13 14 /** 15 * 設置認證token 16 * 17 * @param id 用戶登陸ID 18 * @param subject 用戶登陸名 19 * @param map 其餘私有數據 20 * @return 21 */ 22 public String createJwt(String id, String subject, Map<String, Object> map) { 23 24 //一、設置失效時間啊 25 long now = System.currentTimeMillis(); //毫秒 26 long exp = now + failureTime; 27 28 //二、建立JwtBuilder 29 JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(subject) 30 .setIssuedAt(new Date()) 31 //設置簽名防止篡改 32 .signWith(SignatureAlgorithm.HS256, key); 33 34 //三、根據map設置claims 35 for (Map.Entry<String, Object> entry : map.entrySet()) { 36 jwtBuilder.claim(entry.getKey(), entry.getValue()); 37 } 38 jwtBuilder.setExpiration(new Date(exp)); 39 40 //四、建立token 41 String token = jwtBuilder.compact(); 42 return token; 43 } 44 45 /** 46 * 解析token 47 * 48 * @param token 49 * @return 50 */ 51 public Claims parseJwt(String token) { 52 Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); 53 return claims; 54 } 55 56 }
注意:web
@ConfigurationProperties("jwt.config")須要在配置文件中配置
(3)配置JwtUtils類
1 /** 2 * 配置jwt 3 * 4 * @return 5 */ 6 @Bean 7 public JwtUtils jwtUtils() { 8 return new JwtUtils(); 9 }
(4)編寫登陸方法數據庫
一、編寫DAO層json
1 /** 2 * @author: Mr.Yang 3 * @create: 2020-02-13 21:55 4 **/ 5 @Repository 6 public interface UserDAO { 7 8 public User selectByMobileUser(String mobile); 9 10 public User selectByIdUser(String id); 11 }
二、編寫xml寫Sql後端
<select id="selectByMobileUser" parameterType="string" resultMap="userMap"> select * from bs_user where mobile = #{mobile} </select>
三、編寫service層跨域
/** * 根據mobile查詢用戶 * * @param mobile * @return */ public User selectByMobile(String mobile) { return userDAO.selectByMobileUser(mobile); }
四、編寫controller層cookie
1 /** 2 * 用戶登陸 3 * 1.經過service根據mobile查詢用戶 4 * 2.比較password 5 * 3.生成jwt信息 6 * 7 * @param loginMap 8 * @return 9 * @requestBody把請求數據封裝(前端以json方式傳) 10 */ 11 @RequestMapping(value = "/login", method = RequestMethod.POST) 12 public Result login(@RequestBody Map<String, String> loginMap) { 13 String mobile = loginMap.get("mobile"); 14 String password = loginMap.get("password"); 15 User user = userService.selectByMobile(mobile); 16 //登陸失敗 17 if (user == null || !user.getPassword().equals(password)) { 18 //既可使用拋異常,也可以使用直接返回錯誤碼(推薦) 19 return new Result(ResultCode.MOBILEORPASSWORDERROR); 20 } else { 21 //其餘數據以map集合存放在token中 22 Map<String, Object> dataMap = new HashMap<>(); 23 dataMap.put("companyId", user.getCompanyId()); 24 dataMap.put("companyName", user.getCompanyName()); 25 //生成token並存入數據返回 26 String token = jwtUtils.createJwt(user.getId(), user.getUsername(), dataMap); 27 return new Result(Result.SUCCESS(), token); 28 } 29 }
五、測試網絡
data就是返回的token,裏面存有用戶ID,用戶姓名及以map形式存入的數據(這裏主要看前端須要什麼就存什麼)
(6)用戶登陸成功以後,獲取用戶信息
1 /** 2 * 用戶登陸成功以後,獲取用戶信息 3 * 1.獲取用戶id 4 * 2.根據用戶id查詢用戶 5 * 3.構建返回值對象 6 * 4.響應 7 * 8 * @param request 9 * @return 10 * @throws Exception 11 */ 12 @RequestMapping(value = "/profile", method = RequestMethod.POST) 13 public Result profile(HttpServletRequest request) throws PendingException, Exception { 14 15 /** 16 * 從請求頭信息中獲取token數據 17 * 1.獲取請求頭信息:名稱=Authorization(先後端約定) 18 * 2.替換Bearer+空格 19 * 3.解析token 20 * 4.獲取clamis 21 */ 22 23 24 //1.獲取請求頭信息:名稱=Authorization(先後端約定) 25 String authorization = request.getHeader("Authorization"); 26 if (StringUtils.isEmpty(authorization)) { 27 // throw new PendingException(ResCode.UNAUTHENTICATED); 28 //系統未捕捉到請求頭信息 29 throw new CommonException(ResultCode.UNAUTHENTICATED); 30 } 31 //2.替換Bearer+空格 32 String token = authorization.replace("Bearer ", ""); 33 34 //3.解析token 35 Claims claims = jwtUtils.parseJwt(token); 36 //4.獲取clamis 37 String userId = claims.getId(); 38 39 // String userId = "U01"; 40 User user = userService.selectByIdUser(userId); 41 42 /**此處只是爲了獲取token中的用戶數據,全部只簡單返回用戶對象, 43 * 工做則按實際要求多表查詢須要數據(根據用戶ID查詢權限) 44 */ 45 46 return new Result(ResultCode.SUCCESS, user); 47 }
(7)測試