| 
使用 SpringBoot 提供 api 的时候,我更喜欢使用 jwt 的方式来做验证。网上有会多 Spring Security 整合 jwt 的,也有 Shiro 整合 jwt 的,感觉有点复杂。这里分享一下自己在项目中的简单实现。
×
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册  依赖包
 
 除了 SpringBoot 基本的依赖,需要一个生成 jwt 和序列化的包。生成 jwt 的包依赖很多,因为我项目里使用了 hutool 这个包,就只用用它了。
 jwt用户模型复制代码        <dependency>            <groupId>cn.hutool</groupId>            <artifactId>hutool-all</artifactId>            <version>5.8.9</version>        </dependency>        <dependency>            <groupId>cn.hutool</groupId>            <artifactId>hutool-all</artifactId>            <version>5.8.9</version>        </dependency>
 定义一个 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;@Datapublic class JwtUser {    /**     * 用户编号     */    private Integer id;    /**     * 用户名     */    private String name;    /**     * 角色     */    private String role;    /**     * 获取当前请求用户     * @return     */    public static JwtUser getCurrentUser() {        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();        return (JwtUser) request.getAttribute("user");    }}
 定义一个用于请求类和方法的注解
 JWT 帮助类复制代码import java.lang.annotation.*;@Inherited@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface Authorize {    /**     * 是否匿名可以访问     * @return     */    boolean anonymous() default false;    /**     * 角色     * @return     */    String[] roles() default {};}
 用于生成 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;public class JwtTokenUtils {    public static final String SECRET = "your_secret";    public static final String ISS = "com.your.cn";    private static final int EXPIRATIONHOURS = 24; //过期时间24小时        //创建token    public static String createToken(JwtUser user) {        return createToken(user, EXPIRATIONHOURS);    }    public static String createToken(JwtUser user, int hours) {        String subJson = new Gson().toJson(user);        JWTSigner jwtSigner = JWTSignerUtil.hs512(SECRET.getBytes());        JWT jwt = JWT.create().setSigner(jwtSigner);        jwt                .setJWTId(UUID.randomUUID().toString().replace("-", ""))                .setSubject(subJson) //用户信息                .setIssuer(ISS)      //签发者                //.setAudience("受众")                //.setNotBefore(new Date())                .setIssuedAt(new Date())                .setExpiresAt(new Date(System.currentTimeMillis() + hours * 3600 * 1000));        return jwt.sign();    }    public static JwtUser getUser(String token) {        if (StringHelper.isNullOrEmpty(token)) return null;        var jwt = JWTUtil.parseToken(token);        JWTSigner jwtSigner = JWTSignerUtil.hs512(SECRET.getBytes());        jwt.setSigner(jwtSigner);        if (jwt.validate(10)) {            var subJson = jwt.getPayload("sub").toString();            JwtUser user = new Gson().fromJson(subJson, JwtUser.class);            return user;        } else {            return null;        }    }}
 定义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 验证拦截器 */@Componentpublic class JwtAuthInterceptor implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        //Authorization:Bearer+空格+token        String token = request.getHeader("Authorization");        if (token != null) {            token = token.replace("Bearer ", "");        }        //处理模拟登录的jwt        if (StringHelper.isNullOrEmpty(token)) {            token = request.getParameter("jwt");        }        if (StringHelper.isNullOrEmpty(token)) {            //兼容从请求参数传token            Object jwt = request.getAttribute("jwt");            if (jwt != null) {                token = jwt.toString();            }        }        JwtUser user = JwtTokenUtils.getUser(token);        request.setAttribute("user", user);        if (handler instanceof HandlerMethod) {            HandlerMethod h = (HandlerMethod) handler;            Authorize authorize = 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);                        return false;                    } else if (authorize.roles() != null && authorize.roles().length > 0 &&                            Arrays.stream(authorize.roles()).allMatch(s -> !s.equalsIgnoreCase(user.getRole()))) {                        //没权限                        response.sendError(HttpServletResponse.SC_FORBIDDEN);                        return false;                    }                }            }        }        return true;    }}
 在 WebMvc 配置中注册拦截器,并支持跨域请求
 Controller中使用复制代码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.*;@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {    @Autowired    JwtAuthInterceptor jwtAuthInterceptor;    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(jwtAuthInterceptor).addPathPatterns("/api/**");        WebMvcConfigurer.super.addInterceptors(registry);    }    @Override    public void addCorsMappings(CorsRegistry registry) {        registry.addMapping("/api/**")                .allowedOriginPatterns("*")                .allowedMethods("*")                .allowedHeaders("*")                //.maxAge(3600)                .allowCredentials(true);        WebMvcConfigurer.super.addCorsMappings(registry);    }}
 不用 Spring Security 和 Shiro ,是不是更简单呢!复制代码@RestController@RequestMapping("/api/test")@Authorize(roles = {"admin", "user"})public class TestController {    @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 "匿名可以访问";    }}
 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
 |