SpringBoot集成JWT實現權限認證

上一篇文章《一分鐘帶你瞭解JWT認證!》介紹了JWT的組成和認證原理,本文將介紹下SpringBoot整合JWT實現認證的過程,帶你更深刻的瞭解下JWT。java

1、JWT認證流程

JWT認證流程

認證流程以下:git

  1. 用戶使用帳號和密碼發出post請求;
  2. 服務器使用私鑰建立一個jwt;
  3. 服務器返回這個jwt給瀏覽器;
  4. 瀏覽器將該jwt串在請求頭中像服務器發送請求;
  5. 服務器驗證該jwt;
  6. 返回響應的資源給瀏覽器。

2、SpringBoot整合JWT

新建一個spring boot項目spring-boot-jwt,按照下面步驟操做。github

  1. pom.xml引入jar包
<!-- 引入jwt-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.8.2</version>
</dependency>
  1. 新建Jwt工具類

Jwt工具類進行token的生成和認證,工具類代碼以下:spring

/**
 * @description: Jwt工具類,生成JWT和認證
 * @author: Java碎碎念
 */
public class JwtUtil {

    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);
    /**
     * 密鑰
     */
    private static final String SECRET = "my_secret";

    /**
     * 過時時間
     **/
    private static final long EXPIRATION = 1800L;//單位爲秒

    /**
     * 生成用戶token,設置token超時時間
     */
    public static String createToken(User user) {
        //過時時間
        Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        String token = JWT.create()
                .withHeader(map)// 添加頭部
                //能夠將基本信息放到claims中
                .withClaim("id", user.getId())//userId
                .withClaim("userName", user.getUserName())//userName
                .withClaim("name", user.getName())//name
                .withExpiresAt(expireDate) //超時設置,設置過時的日期
                .withIssuedAt(new Date()) //簽發時間
                .sign(Algorithm.HMAC256(SECRET)); //SECRET加密
        return token;
    }

    /**
     * 校驗token並解析token
     */
    public static Map<String, Claim> verifyToken(String token) {
        DecodedJWT jwt = null;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            jwt = verifier.verify(token);
        } catch (Exception e) {
            logger.error(e.getMessage());
            logger.error("token解碼異常");
            //解碼異常則拋出異常
            return null;
        }
        return jwt.getClaims();
    }

}
  1. 添加JWT過濾器

JWT過濾器中進行token的校驗和判斷,,token不合法直接返回,合法則解密數據並把數據放到request中供後續使用。數據庫

爲了使過濾器生效,須要在啓動類添加註解@ServletComponentScan(basePackages = "com.example.springbootjwt.filter")。瀏覽器

JWT過濾器代碼以下:springboot

/**
 * JWT過濾器,攔截 /secure的請求
 */
@Slf4j
@WebFilter(filterName = "JwtFilter", urlPatterns = "/secure/*")
public class JwtFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) res;

        response.setCharacterEncoding("UTF-8");
        //獲取 header裏的token
        final String token = request.getHeader("authorization");

        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            chain.doFilter(request, response);
        }
        // Except OPTIONS, other request should be checked by JWT
        else {

            if (token == null) {
                response.getWriter().write("沒有token!");
                return;
            }

            Map<String, Claim> userData = JwtUtil.verifyToken(token);
            if (userData == null) {
                response.getWriter().write("token不合法!");
                return;
            }
            Integer id = userData.get("id").asInt();
            String name = userData.get("name").asString();
            String userName = userData.get("userName").asString();
            //攔截器 拿到用戶信息,放到request中
            request.setAttribute("id", id);
            request.setAttribute("name", name);
            request.setAttribute("userName", userName);
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
    }
}
  1. 添加登陸Controller

登陸Controller進行登陸操做,登陸成功後生產token並返回。服務器

登陸Controller代碼以下:併發

/**
 * 登陸Controller
 */
@Slf4j
@RestController
public class LoginController {

    static Map<Integer, User> userMap = new HashMap<>();

    static {
        //模擬數據庫
        User user1 = new User(1, "zhangsan", "張三", "123456");
        userMap.put(1, user1);
        User user2 = new User(2, "lisi", "李四", "123123");
        userMap.put(2, user2);
    }

    /**
     * 模擬用戶 登陸
     */
    @RequestMapping("/login")
    public String login(User user) {
        for (User dbUser : userMap.values()) {
            if (dbUser.getUserName().equals(user.getUserName()) && dbUser.getPassword().equals(user.getPassword())) {
                log.info("登陸成功!生成token!");
                String token = JwtUtil.createToken(dbUser);
                return token;
            }
        }
        return "";
    }
}
  1. 添加SecureController

SecureController中的請求會被JWT過濾器攔截,合法後才能訪問。

SecureController代碼以下:

/**
 * 須要登陸後才能訪問
 */
@Slf4j
@RestController
public class SecureController {

    /**
     * 查詢 用戶信息,登陸後才能訪問
     */
    @RequestMapping("/secure/getUserInfo")
    public String login(HttpServletRequest request) {
        Integer id = (Integer) request.getAttribute("id");
        String name = request.getAttribute("name").toString();
        String userName = request.getAttribute("userName").toString();
        return "當前用戶信息id=" + id + ",name=" + name + ",userName=" + userName;
    }
}

3、測試

測試分兩步,首先訪問登陸接口,登陸成功後獲取token,而後拿着token在訪問查詢用戶信息接口。

  1. 訪問登陸接口

打開PostMan,訪問http://localhost:8080/login?userName=zhangsan&password=123456,登陸成功後接口返回token,請求成功截圖以下:

獲取token截圖

  1. 訪問用戶信息接口

打開PostMan,訪問http://localhost:8080/secure/getUserInfo,header裏須要攜帶token,請求成功截圖以下:

請求用戶信息截圖

到此SpringBoot整合JWT的功能已經所有實現,有問題歡迎留言溝通哦!

完整源碼地址: https://github.com/suisui2019/springboot-study

推薦閱讀

1.一分鐘帶你瞭解JWT認證!
2.SpringBoot中如何優雅的讀取yml配置文件?
3.SpringBoot中如何靈活的實現接口數據的加解密功能?
4.SpringBoot中神奇的@Enable*註解?
5.Java中Integer.parseInt和Integer.valueOf,你還傻傻分不清嗎?


限時領取免費Java相關資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高併發分佈式、大數據、機器學習等技術。
關注下方公衆號便可免費領取:

Java碎碎念公衆號

相關文章
相關標籤/搜索