基於JWT的Token開發案例


代碼地址如下:
http://www.demodashi.com/demo/12531.html

0、准備工作

0-1運行環境

  1. jdk1.8
  2. maven
  3. 一個能支持以上兩者的代碼編輯器,作者使用的是IDEA。

0-2知識儲備

  1. 對SpringBoot框架有所了解
  2. 對token的定義有了解
  3. 本案例簡單,代碼注釋較少,有不明白的地方,或者不正確的地方,歡迎聯系作者本人或留言。

1、設計思路

1-1 項目結構

項目結構

本案例模擬用戶登錄/注冊后,服務器返回一個token用於用戶后續操作。

/controller/HelloController.java:測試token的接口
/controller/UserController.java:用戶注冊/登錄的接口
/entity/User.java:用戶實體類,屬性有 用戶ID,用戶名,密碼,郵箱,上次登錄時間。
/repository/UserRepository:實現SpringData接口的數據庫操作類,可以很方便的進行CRUD等操作。
/Reponse/UserResponse.java:接口返回數據的實體類。
/util/Constants.java:存放常量的工具類。
/util/JwtUtil.java:Jwt工具類,可以生成、解析Jwt。

1-2 實現難點

  1. 對Jwt的理解,可以參考http://blog.leapoahead.com/2015/09/06/understanding-jwt/
  2. JwtUtil工具類的開發

2 具體實現

2-1 JwtUtil.java

@Component
public class JwtUtil {

    private static UserRepository userRepository;

    @Autowired
    public JwtUtil(UserRepository userRepository) {
        JwtUtil.userRepository = userRepository;
    }

    public static final long EXPIRATION_TIME = 3600_000_000L; // 1000 hour
    static final String SECRET = "ThisIsASecret";
    static final String TOKEN_PREFIX = "Bearer";
    static final String HEADER_STRING = "Authorization";

    public static String generateToken(String username,Date generateTime) {
        HashMap<String, Object> map = new HashMap<>();
        //可以把任何安全的數據放到map里面
        map.put("username", username);
        map.put("generateTime",generateTime);
        String jwt = Jwts.builder()
                .setClaims(map)
                .setExpiration(new Date(generateTime.getTime() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        return jwt;
    }

    /**
     * @param token
     * @return
     */
    public static Map<String,Object> validateToken(String token) {
        Map<String,Object> resp = new HashMap<String,Object>();
        if (token != null) {
            // 解析token
            try {
                Map<String, Object> body = Jwts.parser()
                        .setSigningKey(SECRET)
                        .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                        .getBody();
                String username = (String) (body.get("username"));
                Date generateTime = new Date((Long)body.get("generateTime"));

                if(username == null || username.isEmpty()){
                    resp.put("ERR_MSG",Constants.ERR_MSG_USERNAME_EMPTY);
                    return resp;
                }
                //賬號在別處登錄
                if(userRepository.findByUsername(username).getLastLoginTime().after(generateTime)){
                    resp.put("ERR_MSG",Constants.ERR_MSG_LOGIN_DOU);
                    return resp;
                }
                resp.put("username",username);
                resp.put("generateTime",generateTime);
                return resp;
            }catch (SignatureException | MalformedJwtException e) {
                // TODO: handle exception
                // don't trust the JWT!
                // jwt 解析錯誤
                resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_ERR);
                return resp;
            } catch (ExpiredJwtException e) {
                // TODO: handle exception
                // jwt 已經過期,在設置jwt的時候如果設置了過期時間,這里會自動判斷jwt是否已經過期,如果過期則會拋出這個異常,我們可以抓住這個異常並作相關處理。
                resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_EXP);
                return resp;
            }
        }else {
            resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_EMPTY);
            return resp;
        }
    }
}

2.2 UserController.java

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserRepository userRepository;


    //注冊或登錄
    @RequestMapping("/login")
    @Transactional
    public UserResponse login(User user){

        String username = user.getUsername();
        String password = user.getPassword();
        //TODO  檢驗參數的完整性

        UserResponse userResponse = new UserResponse();
        User tUser = userRepository.findByUsername(username);
        //檢驗username是否存在
        user.setLastLoginTime(new Date());
        if(tUser!=null){
            //檢驗密碼是否正確
            if(!tUser.getPassword().equals(password)) {
                userResponse.setErrorNum(Constants.ERR_NUM_PWD_ERR);
                userResponse.setErrorMsg(Constants.ERR_MSG_PWD_ERR);
                return userResponse;
            }
            userRepository.updateLastLoginTimeByUserName(user.getLastLoginTime(),username);

        }else {
            try {
                tUser = userRepository.save(user);
            } catch (Exception e) {
                userResponse.setErrorNum(Constants.ERR_NUM_SERVER_ERR);
                userResponse.setErrorMsg(Constants.ERR_MSG_SERVER_ERR);
                return userResponse;
            }
        }
        userResponse.setErrorNum(Constants.ERR_NUM_OK);
        userResponse.setErrorMsg(Constants.ERR_MSG_OK);
        userResponse.setUserName(username);
        userResponse.setUserId(tUser.getId());
        userResponse.setToken(JwtUtil.generateToken(username,user.getLastLoginTime()));

        return userResponse;
    }
}

2.3 HelloController.java

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public Map login(HttpServletRequest request){
        String token = request.getParameter("token");
        return  JwtUtil.validateToken(token);
    }
}

2.4測試

登錄

用戶登錄后,會返回一串token,咱們可以用token進行下一步請求:

測試token

當我再次訪問登錄接口之后,卻用舊的token訪問測試接口時:

別處登錄

3 總結

上面是貼出的主要代碼,完整的請下載demo包,有不明白的地方請在下方評論,或者聯系郵箱yaoyunxiaoli@163.com。
我是妖雲小離,這是我第二次在Demo大師上發文章,感謝閱讀。
基於JWT的Token開發案例

代碼地址如下:
http://www.demodashi.com/demo/12531.html

注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM