在 SpringBoot 项目中简单实现 JWT 验证

使用 SpringBoot 提供 api 的时候,我更喜欢使用 jwt 的方式来做验证。网上有会多 Spring Security 整合 jwt 的,也有 Shiro 整合 jwt 的,感觉有点复杂。这里分享一下自己在项目中的简单实现。

依赖包

除了 SpringBoot 基本的依赖,需要一个生成 jwt 和序列化的包。生成 jwt 的包依赖很多,因为我项目里使用了 hutool 这个包,就只用用它了。

cn.hutoolhutool-all5.8.9cn.hutoolhutool-all5.8.9

jwt用户模型

定义一个 Jwt 的 sub 字段模型,存储用户:

import lombok.Data;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@DatapublicclassJwtUser {
    /**
     * 用户编号
     */private Integer id;
    /**
     * 用户名
     */private String name;
    /**
     * 角色
     */private String role;

    /**
     * 获取当前请求用户
     * @return
     */publicstatic JwtUser getCurrentUser() {

        RequestAttributesrequestAttributes= RequestContextHolder.currentRequestAttributes();
        HttpServletRequestrequest= ((ServletRequestAttributes) requestAttributes).getRequest();
        return (JwtUser) request.getAttribute("user");
    }
}

验证注解

定义一个用于请求类和方法的注解

import java.lang.annotation.*;

@Inherited@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public@interface Authorize {

    /**
     * 是否匿名可以访问
     * @return
     */booleananonymous()defaultfalse;

    /**
     * 角色
     * @return
     */
    String[] roles() default {};
}

JWT 帮助类

用于生成 jwt 和 解析 JwtUser 对象。

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.google.gson.Gson;
import com.mpyf.xapi.security.JwtUser;
import lombok.var;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

publicclassJwtTokenUtils {

    publicstaticfinalStringSECRET="your_secret";
    publicstaticfinalStringISS="com.your.cn";

    privatestaticfinalintEXPIRATIONHOURS=24; //过期时间24小时//创建tokenpublicstatic String createToken(JwtUser user) {
        return createToken(user, EXPIRATIONHOURS);
    }

    publicstatic String createToken(JwtUser user, int hours) {
        StringsubJson=newGson().toJson(user);
        JWTSignerjwtSigner= JWTSignerUtil.hs512(SECRET.getBytes());

        JWTjwt= JWT.create().setSigner(jwtSigner);
        jwt
                .setJWTId(UUID.randomUUID().toString().replace("-", ""))
                .setSubject(subJson) //用户信息
                .setIssuer(ISS)      //签发者//.setAudience("受众")//.setNotBefore(new Date())
                .setIssuedAt(newDate())
                .setExpiresAt(newDate(System.currentTimeMillis() + hours * 3600 * 1000));
        return jwt.sign();
    }

    publicstatic JwtUser getUser(String token) {

        if (StringHelper.isNullOrEmpty(token)) returnnull;

        varjwt= JWTUtil.parseToken(token);
        JWTSignerjwtSigner= JWTSignerUtil.hs512(SECRET.getBytes());
        jwt.setSigner(jwtSigner);

        if (jwt.validate(10)) {
            varsubJson= jwt.getPayload("sub").toString();
            JwtUseruser=newGson().fromJson(subJson, JwtUser.class);
            return user;
        } else {
            returnnull;
        }
    }
}

验证拦截器

定义jwt的验证拦截器,从请求头获取 token 解析并验证。

import com.mpyf.xapi.helper.JwtTokenUtils;
import com.mpyf.xapi.helper.StringHelper;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

/**
 * jwt 验证拦截器
 */@ComponentpublicclassJwtAuthInterceptorimplementsHandlerInterceptor {

    @OverridepublicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {

        //Authorization:Bearer+空格+tokenStringtoken= request.getHeader("Authorization");
        if (token != null) {
            token = token.replace("Bearer ", "");
        }
        //处理模拟登录的jwtif (StringHelper.isNullOrEmpty(token)) {
            token = request.getParameter("jwt");
        }
        if (StringHelper.isNullOrEmpty(token)) {
            //兼容从请求参数传tokenObjectjwt= request.getAttribute("jwt");
            if (jwt != null) {
                token = jwt.toString();
            }
        }
        JwtUseruser= JwtTokenUtils.getUser(token);
        request.setAttribute("user", user);

        if (handler instanceof HandlerMethod) {
            HandlerMethodh= (HandlerMethod) handler;
            Authorizeauthorize= h.getMethodAnnotation(Authorize.class);
            if (authorize == null) {
                authorize = h.getMethod().getDeclaringClass().getAnnotation(Authorize.class);
            }

            //如果没有Authorize或者可以匿名访问,直接返回if (authorize != null && !authorize.anonymous()) {
                {
                    if (user == null) {
                        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                        returnfalse;
                    } elseif (authorize.roles() != null && authorize.roles().length > 0 &&
                            Arrays.stream(authorize.roles()).allMatch(s -> !s.equalsIgnoreCase(user.getRole()))) {
                        //没权限
                        response.sendError(HttpServletResponse.SC_FORBIDDEN);
                        returnfalse;
                    }
                }
            }
        }
        returntrue;
    }
}

注册拦截器

在 WebMvc 配置中注册拦截器,并支持跨域请求

import com.mpyf.xapi.security.JwtAuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;


@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer {

    @Autowired
    JwtAuthInterceptor jwtAuthInterceptor;


    @OverridepublicvoidaddInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtAuthInterceptor).addPathPatterns("/api/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }

    @OverridepublicvoidaddCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
                .allowedOriginPatterns("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                //.maxAge(3600)
                .allowCredentials(true);
        WebMvcConfigurer.super.addCorsMappings(registry);
    }
}

Controller中使用

@RestController@RequestMapping("/api/test")@Authorize(roles = {"admin", "user"})publicclassTestController {

    @GetMapping("admin_and_user")public String admin_and_user(){
        return"admin 和 user 角色都可以访问";
    }
    @GetMapping("admin_only")@Authorize(roles = "admin")//覆盖Controller的设置public String admin_only(){
        return"只有 admin 角色可以访问";
    }
    @GetMapping("public_all")@Authorize(anonymous = true)public String public_all(){
        return"匿名可以访问";
    }
}

不用 Spring Security 和 Shiro ,是不是更简单呢!

你可能感兴趣的:(java,spring,boot,servlet,spring)