1.網頁常用的幾種驗證方式
(1)HTTP Basic Auth
HTTP Basic Auth簡單點說明就是每次請求API時都提供用戶的username和password,簡言之,Basic Auth是配合
RESTful API 使用的最簡單的認證方式,只需提供用戶名密碼即可,但由於有把用戶名密碼暴露給第三方客戶端的
風險,在生產環境下被使用的越來越少。因此,在開發對外開放的RESTful API時,盡量避免采用HTTP Basic Auth
(2)Cookie Auth
Cookie認證機制就是為一次請求認證在服務端創建一個Session對象,同時在客戶端的瀏覽器端創建了一個Cookie
對象;通過客戶端帶上來Cookie對象來與服務器端的session對象匹配來實現狀態管理的。默認的,當我們關閉瀏
覽器的時候,cookie會被刪除。但可以通過修改cookie 的expire time使cookie在一定時間內有效
(3)OAuth
OAuth(開放授權)是一個開放的授權標准,允許用戶讓第三方應用訪問該用戶在某一web服務上存儲的私密的資
源(如照片,視頻,聯系人列表),而無需將用戶名和密碼提供給第三方應用。 OAuth允許用戶提供一個令牌,而
不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每一個令牌授權一個特定的第三方系統(例如,視頻
編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,
OAuth讓用戶可以授權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非所有內容這種基於OAuth的
認證機制適用於個人消費者類的互聯網產品,如社交類APP等應用,但是不太適合擁有自有認證
權限管理的企業應用。
(4)Token Auth
使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的:
1. 客戶端使用用戶名跟密碼請求登錄
2. 服務端收到請求,去驗證用戶名與密碼
3. 驗證成功后,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
4. 客戶端收到 Token 以后可以把它存儲起來,比如放在 Cookie 里
5. 客戶端每次向服務端請求資源的時候需要帶着服務端簽發的 Token
6. 服務端收到請求,然后去驗證客戶端請求里面帶着的 Token,如果驗證成功,就向客戶端返回請求的數據
Token Auth的優點
支持跨域訪問: 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)
2.什么是JWT
JSON Web Token(JWT)是一個非常輕巧的規范。這個規范允許我們使用JWT在用戶和服務器之間傳遞安全可靠的
信息。在Java世界中通過JJWT實現JWT創建和驗證。
token的創建
創建maven工程,引入依賴
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
創建類createJwtDemo,用於生成token
package com.common.token; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; public class createJwtDemo { /** * 通過jjwt創建token * @param args */ public static void main(String[] args) { JwtBuilder jwtBuilder = Jwts.builder().setId("id") .setSubject("趙") //用戶信息 .setIssuedAt(new Date()) //簽名時間 .signWith(SignatureAlgorithm.HS256, "bgyz") .claim("userId","123456") .claim("name","趙天") ;//設置簽名防止被篡改 /** * bgyz 注意最少4個字符,否則會報 * Exception in thread "main" java.lang.IllegalArgumentException: secret key byte array cannot be null or empty. * 錯誤 */ String token = jwtBuilder.compact(); System.out.println(token); } }
token的解析
View Code
package com.common.token; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; public class ParseJwt { /** * 解析 jwtToken字符串 * @param args */ public static void main(String[] args) { String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJpZCIsInN1YiI6Iui1tSIsImlhdCI6MTU4MDAyNjIxMiwidXNlcklkIjoiMTIzNDU2IiwibmFtZSI6Iui1teWkqSJ9.XFILGV-nflhhd_kO4df7aGcm_Z7ZRJ3gdx4HtU2Spfo"; Claims claims = Jwts.parser().setSigningKey("bgyz").parseClaimsJws(token).getBody(); //私有數據存放在 claims System.out.println(claims.getId()); System.out.println(claims.getSubject()); System.out.println(claims.getIssuedAt()); /** * 解析自定義的claim中的內容 */ System.out.println(claims.get("userId").toString()); System.out.println(claims.get("name").toString()); } }
上面只是測試token,現在創建一個token驗證的工具類

package com.common.utils; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.Getter; import lombok.Setter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.Date; import java.util.Map; /** * 1.如果說,我們只是在某個業務邏輯中需要獲取一下配置文件中的某個項值,使用@Value * * 2、如果說,我們專門編寫了一個javaBean來和配置文件進行映射,我們就直接使用@ConfigurationProperties */ @Getter @Setter @ConfigurationProperties("jwt.config") public class JwtUtils { //簽名私鑰 private String key; //簽名的失效時間 // @Value("${jwt.config.ttl}") private Long ttl; /** * 設置認證token * id:登錄用戶id * subject:登錄用戶名 * */ public String createJwt(String id,String name,Map<String ,Object> map) { //1.設置失效時間 long now = System.currentTimeMillis();//當前毫秒 // System.out.println(ttl); long exp = now + ttl; //2.創建jwtBuilder JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(name) .setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, key); //3.根據map設置claims for(Map.Entry<String,Object> entry : map.entrySet()) { jwtBuilder.claim(entry.getKey(),entry.getValue()); } jwtBuilder.setExpiration(new Date(exp)); //4.創建token String token = jwtBuilder.compact(); return token; } /** * 解析token字符串獲取clamis */ public Claims parseJwt(String token) { Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); return claims; } }
jwt.config 配置在 application.yml文件中
jwt:
config:
key: bgyg
ttl: 50000
springboot 啟動類添加
@Bean public JwtUtil jwtUtil(){ return new util.JwtUtil(); }
用戶登錄獲取token和請求時攜帶token 后台解析token中的用戶信息(寫的簡單例子,可以根據具體業務封裝返回數據)
package com.zhao.system.controller; import com.common.utils.JwtUtils; import io.jsonwebtoken.Claims; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @RestController public class usercontroller { @Autowired private JwtUtils jwtUtils; /** * 使用jjwt token 進行驗證登錄 */ @ResponseBody @GetMapping("/login") public String login(){ Map<String ,Object> map= new HashMap(); map.put("userName","張三"); String token = jwtUtils.createJwt("1","zhao",map); return token; } // /** * 解析token 用get獲取的 主要是測試 */ // @ResponseBody // @GetMapping("/userInformation/{token}") // public String parseDemoToken(@PathVariable("token") String token){ // Claims claims = jwtUtils.parseJwt(token); // claims.get("userName"); 獲取設置的用戶 // return claims.get("userName").toString(); // } /** * 解析token */ @ResponseBody @GetMapping("/userInformation") public String parseToken(HttpServletRequest request){ /** * 從請求頭信息中獲取token信息 token放在哪和前端約定就行了 * 1.獲取請求頭 中的 名稱=Authorization * 2.替換 Bearer +空格 * 3.解析 token * 4.獲取clamis * */ String authorization = request.getHeader("Authorization"); //spring 判斷為空的方法 if(StringUtils.isEmpty(authorization)){ return "請進行登錄"; } //獲取到token 信息 String token = authorization.replace("Bearer", ""); Claims claims = jwtUtils.parseJwt(token); // claims.get("userName"); 獲取設置的用戶 return claims.get("userName").toString(); } }