Java 的 JJWT 實現 JWT


JJWT是一個提供端到端的JWT創建和驗證的Java庫

依賴

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>RELEASE</version>
        </dependency>

token的創建

setIssuedAt用於設置簽發時間
signWith用於設置簽名秘鑰

        JwtBuilder builder = Jwts.builder().setId("111")
                .setSubject("小明")
                .setIssuedAt(newDate())
                .signWith(SignatureAlgorithm.HS256, "ld");

        String token = builder.compact();

token的解析

        String token = "~~~";
        Claims claims = Jwts.parser().setSigningKey("ld").parseClaimsJws(token).getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("subject:" + claims.getSubject());
        System.out.println("IssuedAt:" + claims.getIssuedAt());

token過期校驗

        long now = System.currentTimeMillis();  //當前時間
        long exp = now + 1000 * 60; //過期時間為1分鍾
        JwtBuilder builder = Jwts.builder().setId("111")
                .setSubject("小明")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, "ld")
                .setExpiration(new Date(exp));

當未過期時可以正常讀取
當過期時會引發 io.jsonwebtoken.ExpiredJwtException 異常

自定義claims

        long now = System.currentTimeMillis();  //當前時間
        long exp = now + 1000 * 60; //過期時間為1分鍾
        JwtBuilder builder = Jwts.builder().setId("111")
                .setSubject("小明")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, "ld")
                .setExpiration(new Date(exp))
                .claim("role", "admin");

獲取:
    claims.get("role")

示例

JWT工具類

@Data
public class JwtUtil {

    private String key; //密鑰加鹽

    private long ttl;   //過期時間

    /**
     * 生成JWT
     */
    public String createJWT(String id, String subject, String role) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder().setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, key).claim("role", role);
        if (ttl > 0) {
            builder.setExpiration(new Date(nowMillis + ttl));
        }
        return builder.compact();
    }

    /**
     * 解析JWT
     */
    public Claims parseJWT(String jwtStr) {
        return Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtStr)
                .getBody();
    }
}


添加配置

jwt:
  config:
    key: littledonkey
    ttl: 3600000


簽發token

        //判斷是否密碼是否正確
        Admin loginAdmin = adminService.login(admin);
        if (loginAdmin == null) {
            return new Result(false, StatusCode.LOGINERROR, "登陸失敗");
        }
        //簽發token
        String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
        HashMap<String, String> map = new HashMap<>();
        map.put("token", token);
        map.put("role", "admin");
        return new Result(true, StatusCode.OK, "登陸成功", map);

使用攔截器方式實現token鑒權

org.springframework.web.servlet.handler.HandlerInterceptorAdapter這個適配器,
繼承此類,可以非常方便的實現自己的攔截器。
三個方法分別實現預處理、后處理(調用了Service並返回ModelAndView,但未進行頁面渲染)、返回處理(已經渲染了頁面):

  1. 在preHandle中,可以進行編碼、安全控制等處理
  2. 在postHandle中,有機會修改ModelAndView
  3. 在afterCompletion中,可以根據ex是否為null判斷是否發生了異常,進行日志記錄
添加攔截器

@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //獲取請求頭(如果有此請求頭,表示token已經簽發)
        String header = request.getHeader("tokenHeader");
        if (header != null || !"".equals(header)) {
            //解析請求頭(防止偽造token,token內容以"token "作為開頭)
            if (header.startsWith("token ")) {
                try {
                    Claims claims = jwtUtil.parseJWT(header.substring(6));
                    String role = (String) claims.get("role");
                    //為具有相關權限的用戶添加權限到request域中
                    if ("admin".equals(role)) {
                        //拿到"admin_token"頭信息,表示當前角色是admin
                        request.setAttribute("admin_token", header.substring(6));
                    }
                    if ("user".equals(role)) {
                        //拿到"user_token"頭信息,表示當前角色是user
                        request.setAttribute("user_token", header.substring(6));
                    }
                } catch (Exception e) {
                    throw new RuntimeException("令牌不正確");
                }
            }
        }
        //所有請求都通過,具體權限在service層判斷
        return true;
    }
}


注冊攔截器

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
    @Autowired
    private TokenInterceptor tokenInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login/**");
    }
}


service層驗證

    public void deleteById(String id) {
        String admin_token = (String) request.getAttribute("admin_token");
        if(admin_token == null || "".equals(admin_token)){
            throw new RuntimeException("權限不足");
        }
        adminDao.deleteById(id);
    }


免責聲明!

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



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