- 項目軟件要對外提供部分定製接口,爲了保證軟件數據的安全性,決定要設置token令牌來校驗請求方是否合法。考慮諸多種方案後,決定使用比較流行的JWT來實現。
- 實現思路:客戶端每次訪問接口的時候,要在header中攜帶token令牌,然後在項目的攔截器中使用相應的策略配置攔截這些對外接口的請求(例如這一類接口的url統一配置爲/api/開頭),攔截到請求後從header中得到token進行校驗,校驗通過後即可放行。通過不了返回相應狀態碼,客戶端得到狀態碼攜帶賬號和密碼向服務端申請token,服務端驗證賬號密碼合法後生成token返回,token具有時效性。
- 有了思路之後,開始進行開發,首先,pom.xml中配置jwt包,注意,jwt包需要依賴一個codec的jar包,版本過低的話會出現NoSuchMethodError,詳情見上篇文章。
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
public class TokenManager {
//私鑰
private static final String SECRET = "Axmk89Li3Aji9M";
//過期時間1分鐘
private static final int expiresTime = 60000;
public static String createToken(Long userId){
//獲取加上過期時間後的時間
Date nowDate = new Date();
System.out.println(nowDate);
Date expiresDate = new Date(System.currentTimeMillis()+expiresTime);
Map<String,Object> map = new HashMap<String,Object>();
map.put("alg", "HS256");
map.put("typ", "JWT");
String token = JWT.create().withHeader(map) //請求頭
.withClaim("iss", "Service") //簽發方
.withClaim("aud", "Client") //接收方
.withClaim("userId", null==userId?null:userId.longValue()) //存儲信息,用戶ID
.withIssuedAt(nowDate) //當前時間
.withExpiresAt(expiresDate) //過期時間
.sign(Algorithm.HMAC256(SECRET)); //私鑰
return token;
}
public static boolean verifyToken(String token){
try{
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
verifier.verify(token);
//DecodedJWT verify = verifier.verify(token);
//return verify.getClaims(); //能返回數據集合(用於在jwt中存儲一些數據)的,但是由於這一版本只需要覈驗token是否合法,所以只需要返回true和false;
return true;
}catch(Exception e){
log.error(e.getMessage(), e);
return false;
}
}
}
- 有了token工具類之後,在攔截器中配置攔截url爲/api/開頭的請求,然後從header中得到token進行校驗,校驗通過即放行,不通過返回相應的狀態碼。
//以下爲驗證token的
if(uri.startsWith("api/")){
try{
String token = request.getHeader("token");
//如果token不爲空,則可以進入下一步覈驗
if(!StringUtils.isBlank(token)){
if(!TokenManager.verifyToken(token)){
log.info("token驗證未通過,token爲:"+token);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().print("{\"code\":" + Constants.ERR_CODE_USER_NOT_LOGIN + ",\"msg\":\"未登錄或登錄超時,請重新登錄!\"}");
return false;
}
return true;
}
return false;
}catch(Exception e){
log.error(e.getMessage(), e);
return false;
}
}
- 然後編寫token獲取接口,讓客戶端傳賬號和密碼過來,校驗通過後生成token,這個就不贅述了。一個簡單的jwt生成token實現驗證就完成了,其實還可以在token中傳一些非敏感信息,拿到token後取出進行更加仔細的核驗。