1. 程式人生 > >基於Token的身份認證方法

基於Token的身份認證方法

1.基於 Token 的身份驗證方法

 使用基於 Token 的身份驗證方法,在服務端不需要儲存使用者的登入記錄。大概的流程是這樣的:

  1. 客戶端使用使用者名稱跟密碼請求登入
  2. 服務端收到請求,去驗證使用者名稱與密碼
  3. 驗證成功後,服務端會簽發一個 Token,再把這個 Token 傳送給客戶端
  4. 客戶端收到 Token 以後可以把它儲存起來,比如放在 Cookie 裡或者 Local Storage 裡
  5. 客戶端每次向服務端請求資源的時候需要帶著服務端簽發的 Token
  6. 服務端收到請求,然後去驗證客戶端請求裡面帶著的 Token,如果驗證成功,就向客戶端返回請求的資料

2.程式碼示例

2.1、使用者登入成功後,以token作為key將使用者資訊放到redis中並返回,返回的使用者資訊中也包括token。

UserDTO userDTO = new UserDTO();
userDTO.setCode(loginUser.getCode());
userDTO.setName(loginUser.getName());
userDTO.setDeptCode(loginUser.getDeptCode());
userDTO.setDeptName(loginUser.getDeptName());
userDTO.setRoles(roles); 
userDTO.setAuthoritys(authoritys);
// redis中存放的key
token = CodeUtil.getCode();//UUID生成
userDTO.setToken(token);
// 存放redis,暫時2小時
redis.set(token, JsonUtils.objectToJson(userDTO), 7200);
//返回加密後的資訊
encoder.encodeToString(JsonUtils.objectToJson(userDTO).getBytes("UTF-8"))

2.2、後臺通過token從redis中獲取請求使用者資訊。

HttpServletRequest request =
        ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
    return null;
}
String userRedis = (String) redis.get(token);
if (StringUtils.isEmpty(userRedis)) {
    return null;
}
UserDTO userFromRedis = JsonUtils.jsonToPojo(userRedis, UserDTO.class);

2.3、token驗證攔截器

@Aspect
@Component
public class MyAspect {
 
    @Autowired
    RedisOperator redis;
     
    @Pointcut("execution(* com.project.*..*Controller.*(..)) && !execution(*   com.project.*..*.login*(..))")
    public void login() {
    }

    
   @Around("login()")

    public Object loginVerify(ProceedingJoinPoint joinPoint) throws Throwable{ 
       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 
      String token = request.getHeader("token"); 
      if (StringUtils.isEmpty(token)) { 
      return CommonResponse.errorTokenMsg("token不能為空,請登入"); 
      } 
      String userRedis = redis.get(token); 
      if (StringUtils.isEmpty(userRedis)) { 
      return CommonResponse.errorTokenMsg("登陸超時,請重新登入!"); 
      } 
      // 重新整理token時長 
      redis.expire(token, 7200); 
      // json轉物件 
      todo UserDTO userFromRedis = JsonUtils.jsonToPojo(userRedis, UserDTO.class); 
      ...... 
      return joinPoint.proceed(); 
    }

}

3.小結

  • 如果API設計成規範的無狀態RESTful,考慮使用token
  • 如果API被不同終端消費,Cookie受限,考量token
  • cookie存在瀏覽器,不安全;
  • session存在伺服器,可能影響效能;
  • token身份認證安全性好,是唯一的。