與cookie相比較的優勢:
1、支持跨域訪問,將token置於請求頭中,而cookie是不支持跨域訪問的;
2、無狀態化,服務端無需存儲token,只需要驗證token信息是否正確即可,而session需要在服務端存儲,一般是通過cookie中的sessionID在服務端查找對應的session;
3、無需綁定到一個特殊的身份驗證方案(傳統的用戶名密碼登陸),只需要生成的token是符合我們預期設定的即可;
4、更適用於移動端(Android,iOS,小程序等等),像這種原生平台不支持cookie,比如說微信小程序,每一次請求都是一次會話,當然我們可以每次去手動為他添加cookie,詳情請查看博主另一篇博客;
5、避免CSRF跨站偽造攻擊,還是因為不依賴cookie;
6、非常適用於RESTful API,這樣可以輕易與各種后端(java,.net,python......)相結合,去耦合
基於jwt的token認證實現:
1、加入jwt的依賴
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.3.0</version>
</dependency>
2、聲明2個變量過期時間和token秘鑰(UUID可能會更好,我是自己隨便輸的),token秘鑰用於后面解密
//設置30分鍾過期
private static final long EXPIRE_DATE=30*60*1000;
//token秘鑰
private static final String TOKEN_SECRET = "EQIUBFKSJBFJH2367816BQWE";
3、加密
public static String tokenTest (String username,String password){
String token = "";
try {
//過期時間
Date date = new Date(System.currentTimeMillis()+EXPIRE_DATE);
//秘鑰及加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
//設置頭部信息
Map<String,Object> header = new HashMap<>();
header.put("typ","JWT");
header.put("alg","HS256");
//攜帶username,password信息,生成簽名
token = JWT.create()
.withHeader(header)
.withClaim("username",username)
.withClaim("password",password).withExpiresAt(date)
.sign(algorithm);
}catch (Exception e){
e.printStackTrace();
return null;
}
return token;
}
4、解密。該方法的參數token是加密方法的返回值
public static boolean verify(String token){
/**
* @desc 驗證token,通過返回true
* @create 2019/1/18/018 9:39
* @params [token]需要校驗的串
**/
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return true;
}catch (Exception e){
e.printStackTrace();
return false;
}
}
5、登錄接口
@RequestMapping(value = "/logon")
public JsonRESTResult getUserInfo(HttpSession session ,String userName, String password) {
/**
* @author zdj
* @create 2019/1/17/017 9:55
* @params [session, userName, password]
**/
JsonRESTResult jsonRESTResult = new JsonRESTResult();
//使用token工具類生成token串
String token = TokenUtil.tokenTest(userName,password);
//根據用戶名密碼查找用戶
User user = loginService.findUser(userName,password);
if (user !=null){
//將用戶對象放到session中
session.setAttribute("USER_INFO",user);
//用戶無操作30分鍾需重新登錄
session.setMaxInactiveInterval(60*30);
Map map = new HashMap<>();
map.put("USERINFO",user);
map.put("SESSIONID",session.getId());
map.put("token",token);
jsonRESTResult.setCode(JsonRESTResultMsg.CODE_800.getCode());
jsonRESTResult.setMsg("登錄成功");
jsonRESTResult.setData(map);
return jsonRESTResult;
}else{
jsonRESTResult.setCode(JsonRESTResultMsg.CODE_500.getCode());
jsonRESTResult.setMsg("登錄失敗,用戶名密碼錯誤");
jsonRESTResult.setData(null);
return jsonRESTResult;
}
}
6、判斷用戶是否登錄接口
@RequestMapping("/judgeLogin")
public JsonRESTResult judgeLogin(String token,HttpSession session){
JsonRESTResult jsonRESTResult = new JsonRESTResult();
if (TokenUtil.verify(token)){
User user = (User)session.getAttribute("USER_INFO");
jsonRESTResult.setCode(JsonRESTResultMsg.CODE_800.getCode());
jsonRESTResult.setData(user);
jsonRESTResult.setMsg("用戶登錄成功");
}else {
jsonRESTResult.setCode(JsonRESTResultMsg.CODE_500.getCode());
jsonRESTResult.setMsg("未登錄或已過期");
}
return jsonRESTResult;
}
完整工具類
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @desc 使用token驗證用戶是否登錄
* @author zdj
* @create 2019/1/18/018 9:41
**/
public class TokenUtil {
//設置30分鍾過期
private static final long EXPIRE_DATE=30*60*1000;
//token秘鑰
private static final String TOKEN_SECRET = "EQIUBFKSJBFJH2367816BQWE";
// private static String username = "zdj" ;
// private static String password = "123" ;
public static String tokenTest (String username,String password){
String token = "";
try {
//過期時間
Date date = new Date(System.currentTimeMillis()+EXPIRE_DATE);
//秘鑰及加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
//設置頭部信息
Map<String,Object> header = new HashMap<>();
header.put("typ","JWT");
header.put("alg","HS256");
//攜帶username,password信息,生成簽名
token = JWT.create()
.withHeader(header)
.withClaim("username",username)
.withClaim("password",password).withExpiresAt(date)
.sign(algorithm);
}catch (Exception e){
e.printStackTrace();
return null;
}
return token;
}
public static boolean verify(String token){
/**
* @desc 驗證token,通過返回true
* @create 2019/1/18/018 9:39
* @params [token]需要校驗的串
**/
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return true;
}catch (Exception e){
e.printStackTrace();
return false;
}
}
public static void main(String[] args) {
/**
* @desc token工具類測試
* @create 2019/1/18/018 9:40
* @params [args]
**/
// System.out.println(tokenTest(username,password));
// System.out.println(verify(tokenTest(username,password)));
}
}
————————————————
版權聲明:本文為博主「殘月灬清風」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zdj18166896501/article/details/86534596