SpringBoot通过拦截器和JWT令牌实现登录验证

6 篇文章 0 订阅
本文介绍了如何在SpringMVC应用中使用JWT工具类生成和验证令牌,自定义匿名访问注解,以及实现JWT验证拦截器,以控制API的访问权限。
摘要由CSDN通过智能技术生成

1. Jwt 工具类

引入依赖

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>4.4.0</version>
</dependency>

JwtUtil 类包含了两个静态方法:generateToken() 用于生成 JWT,verifyToken() 用于验证 JWT

public class JwtUtil {

    //密钥
    private static final String SECRET_KEY = "xxxxxxxxx";

    // 过期时间60分钟
    private static final long EXPIRE_TIME = 60 * 60 * 1000;

    /**
     * 生成签名
     *
     * @param claims
     * @return
     */
    public static String generateToken(Map<String, Object> claims) {

        var jwtBuilder = JWT.create();

        // 设置传入的字典中的声明
        for (Map.Entry<String, Object> entry : claims.entrySet()) {
            jwtBuilder.withClaim(entry.getKey(), entry.getValue().toString());
        }

        //过期时间
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);

        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
        return jwtBuilder.withExpiresAt(date).sign(algorithm);


    }

    /**
     * 校验token是否正确
     *
     * @param token
     * @return
     */
    public static boolean verifyToken(String token) {
        try {
            if (token.startsWith("Bearer ")) {
                token = token.replace("Bearer ", "");
                return false;
            }

            Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
            DecodedJWT jwt = JWT.require(algorithm)
                    .build()
                    .verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }
    
    /**
     * 获得token中的用户信息(无需secret解密也能获得)
     *
     * @param token
     * @return
     */
    public static String getUsername(String token) {
        try {
            if (token.startsWith("Bearer ")) {
                token = token.replace("Bearer ", "");
            }
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }
}

2. 匿名访问注解

自定义匿名访问注解,接口添加该注解,则跳过Jwt权限验证。

/**
 * 自定义注解
 * 允许匿名访问
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AllowAnon {
    boolean required() default true;
}

3. Jwt验证拦截器


public class JwtInterceptor implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws IOException
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {

        System.out.println("Jwt Interceptor preHandle");

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        //检查有没有允许匿名访问的注解
        if (method.isAnnotationPresent(AllowAnon.class)) {
            AllowAnon allowAnon = method.getAnnotation(AllowAnon.class);
            if (allowAnon.required()) {
                //允许匿名访问(无需权限)
                return true;
            }
        }

        String authorizationHeader = request.getHeader("Authorization");
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            ResponseErrorMessage(response);
            return false;
        }
        String token = authorizationHeader.substring(7);
        try {
            //验证token
            if (JwtUtil.verifyToken(token)) {
                //验证成功
                return true;
            } else {
                //验证失败
                ResponseErrorMessage(response);
                return false;
            }
        } catch (Exception e) {
            ResponseErrorMessage(response);
            return false;
        }
    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     * preHandle方法处理之后这个方法会被调用,如果控制器Controller出现了异常,则不会执行此方法
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Jwt Interceptor postHandle");
    }

    /**
     * 不管有没有异常,这个afterCompletion都会被调用
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Jwt Interceptor afterCompletion");
    }

    /**
     * 响应错误消息
     *
     * @param response
     * @throws IOException
     */
    private void ResponseErrorMessage(HttpServletResponse response) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json; charset=UTF-8");
        response.getWriter().write("{\"success\":false,\"message\":\"授权失败\",\"data\":null}");
    }
}

4. 注册拦截器


//注册拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    /**
     * 重写addInterceptors()实现拦截器
     * 配置:要拦截的路径以及不拦截的路径
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        System.out.println("InterceptorConfig addInterceptors");

        registry.addInterceptor(jwtInterceptor())  //配置拦截规则
                .addPathPatterns("/api/**")  // 拦截所有请求,通过判断token是否合法来决定是否需要登录
                .excludePathPatterns(
                        "/api/user/register"  //注册
                );//允许匿名访问放行的请求
    }

    @Bean
    public JwtInterceptor jwtInterceptor() {
        return new JwtInterceptor();
    }
}

5. 控制器

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

    /**
     * 注册(无需jwt验证,InterceptorConfig定义排除JwtInterceptor验证路由)
     *
     * @return
     */
    @PostMapping("register")
    public String register() {
        return "注册成功";
    }

    /**
     * 登录(无需jwt验证,添加AllowAnon允许匿名访问注解)
     *
     * @return
     */
    @AllowAnon
    @PostMapping("login")
    public String login() {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", "9");
        claims.put("userName", "usernine");

        //生成token
        var token = JwtUtil.generateToken(claims);

        return token;
    }

    /**
     * 详情(需要验证)
     *
     * @return
     */
    @GetMapping("detail")
    public void getUserDetail(@RequestHeader("Authorization") String token) {
        //获取当前用户名
        var username = JwtUtil.getUsername(token);
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Spring Boot项目中的static资源中编写JS代码实现每次访问某一个页面时都携带JWT令牌,可以在JavaScript代码中设置请求头。具体代码实现如下: 1. 在JavaScript代码中获取JWT令牌: ```javascript const token = localStorage.getItem('token'); ``` 2. 在发送请求时设置请求头: ```javascript const xhr = new XMLHttpRequest(); xhr.open('GET', '/api/profile'); xhr.setRequestHeader('Authorization', `Bearer ${token}`); xhr.send(); ``` 3. 在后端拦截器中获取请求头中的JWT令牌: ```java public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization").replace("Bearer ", ""); // 进行JWT令牌验证和解析 // ... } ``` 4. 完整的代码实现如下: 在static/js/main.js中: ```javascript const token = localStorage.getItem('token'); const xhr = new XMLHttpRequest(); xhr.open('GET', '/api/profile'); xhr.setRequestHeader('Authorization', `Bearer ${token}`); xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { console.log(xhr.responseText); } else { console.error(xhr.statusText); } } }; xhr.send(); ``` 在后端的拦截器中: ```java public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization").replace("Bearer ", ""); // 进行JWT令牌验证和解析 // ... return true; } } ``` 在Spring Boot的配置类中添加拦截器: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JwtInterceptor()) .addPathPatterns("/api/**") // 拦截/api开头的请求 .excludePathPatterns("/api/login"); // 排除/api/login请求 } } ``` 这样,在访问/static/js/main.js时,会自动携带JWT令牌。在后端可以通过拦截器获取请求头中的JWT令牌,并进行验证和解析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值