SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截(保姆级教学,附:源码)2

简介: SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截

上述准备工作以及完成

6:pojo 实体类

@Data
public class Users {
    private String id;
    private String username;
    private String password;
}

7: annotation 自定义注解

/**
 * @author xia
 * @version 1.0
 * @Data 用来跳过验证的 PassToken
 * @date 2023/2/13 16:16
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}
/**
 * @author xia
 * @version 1.0
 * @DATA  用于登录后才能操作的token
 * @date 2023/2/13 16:16
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

8:拦截器

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())
                .excludePathPatterns("/user/**")
                .addPathPatterns("/**");
    }
    @Bean
    public JWTInterceptor jwtInterceptor() {
        return new JWTInterceptor();
    }
}
@Component
@SuppressWarnings("all")
public class JWTInterceptor implements HandlerInterceptor {
    @Autowired
    User user;
    // 请求前到达之前拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object)
            throws Exception {
        // 从请求头获取 token
        String token = request.getHeader("token");
        //首先映射是不是方法,如果不是则返回
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod) object;
        Method method=handlerMethod.getMethod();
        //检查是否有passtoken注释,有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        // token 验证失败后的返回信息
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                if (StrUtil.isBlank(token)) {
                    throw new RuntimeException( "无token,请重新登录");
                }
                // 获取 token 中的 user id
                int userId;
                try {
                    DecodedJWT decode = JWT.decode(token);
                    String id = decode.getClaim("id").asString();
                    userId = Integer.parseInt(id);
                } catch (JWTDecodeException j) {
                    throw new RuntimeException("401");
                }
                System.out.println(userId);
                Users users = user.findUserById(userId);
                if (users == null) {
                    throw new RuntimeException("用户不存在,请重新登录");
                }
                try {
                    // JWT 工具包验证 token
                    JWTUtils.verify(token);
                    return true;
                } catch (TokenExpiredException e) {
                    throw new RuntimeException("Token已经过期!!!");
                } catch (SignatureVerificationException e){
                    throw new RuntimeException("签名错误!!!");
                } catch (AlgorithmMismatchException e){
                    throw new RuntimeException("加密算法不匹配!!!");
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("无效token~~");
                }
            }
        }
        return true;
    }
}

9:controller 层

@RestController
@Slf4j
@SuppressWarnings("all")
public class JwtController {
    @Resource
    private UsersMapper mapper;
    // 认证
    @PassToken
    @PostMapping("/user/login")
    public Result login(@RequestBody Users user) {
        System.out.println("前端传来的用户数据:"+user);
        try {
            // 查询数据库
            QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
            HashMap<String, Object> queryMap = new HashMap<>();
            queryMap.put("username", user.getUsername());
            queryMap.put("password", user.getPassword());
            queryWrapper.allEq(queryMap);
            Users userDb = mapper.selectOne(queryWrapper);
            // 认证失败
            if(userDb == null) {
                throw new RuntimeException("没有此用户。请重新登录");
            }
            // 认证成功
            Map<String, String> tokenClaimsMap = new HashMap<>(); //用来存放payload
            tokenClaimsMap.put("id",userDb.getId());
            tokenClaimsMap.put("username", userDb.getUsername());
            String token = JWTUtils.getToken(tokenClaimsMap);
            // 返回的数据
           return new Result(ResultCode.SUCCESS,token);
        } catch (Exception e) {
            // 认证失败,返回的数据
            e.printStackTrace();
            return new Result(ResultCode.ERROR,e);
        }
    }
  @UserLoginToken
    @GetMapping("/private/info")
    public String info(HttpServletRequest request){
        String token = request.getHeader("token");
        DecodedJWT tokenJWT = JWTUtils.getToken(token);
        System.out.println(tokenJWT.getClaim("username").asString());
        System.out.println(tokenJWT.getClaim("userId").asInt());
        return "这是一段私人信息。只有登录才能显示";
    }
    @UserLoginToken
    @GetMapping("/private/Test")
    public Result info(){
        String code = "这是一段私人信息。只有登录才能显示";
        return new Result(ResultCode.SUCCESS,code);
    }
    @PassToken()
    @PostMapping("/private/Test2")
    public Result info2(){
        String code = "这是一段普通信息。不登录也能显示";
        return new Result(ResultCode.SUCCESS,code);
    }
}

10: service 以及实现类

@Service
public interface User {
    Users findUserById(int userId);
}
@Service
public class UserService implements User{
    @Resource
    private UsersMapper mapper;
    @Override
    public Users findUserById(int userId) {
        Users users = mapper.selectById(userId);
        System.out.println("------------>"+ users);
        return users;
    }
}

11: mapper层

@Mapper
public interface UsersMapper extends BaseMapper<Users> {
}

启动项目,演示效果如下:

1:账号登录成功生成Token (登录请求,使用@PassToken() 注解 跳过token验证)

@PassToken
    @PostMapping("/user/login")
    public Result login(@RequestBody Users user) {
        System.out.println("前端传来的用户数据:"+user);
        try {
            // 查询数据库
            QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
            HashMap<String, Object> queryMap = new HashMap<>();
            queryMap.put("username", user.getUsername());
            queryMap.put("password", user.getPassword());
            queryWrapper.allEq(queryMap);
            Users userDb = mapper.selectOne(queryWrapper);
            // 认证失败
            if(userDb == null) {
                throw new RuntimeException("没有此用户。请重新登录");
            }
            // 认证成功
            Map<String, String> tokenClaimsMap = new HashMap<>(); //用来存放payload
            tokenClaimsMap.put("id",userDb.getId());
            tokenClaimsMap.put("username", userDb.getUsername());
            String token = JWTUtils.getToken(tokenClaimsMap);
            // 返回的数据
           return new Result(ResultCode.SUCCESS,token);
        } catch (Exception e) {
            // 认证失败,返回的数据
            e.printStackTrace();
            return new Result(ResultCode.ERROR,e);
        }

4bb5a4f78076420e9ff592cf5372d0d6.png

2:使用这个注解 :@UserLoginToken(登录需要验证)

@UserLoginToken
    @GetMapping("/private/info")
    public String info(HttpServletRequest request){
        String token = request.getHeader("token");
        DecodedJWT tokenJWT = JWTUtils.getToken(token);
        System.out.println(tokenJWT.getClaim("username").asString());
        System.out.println(tokenJWT.getClaim("userId").asInt());
        return "这是一段私人信息。只有登录才能显示";
    }
    @UserLoginToken
    @GetMapping("/private/Test")
    public Result info(){
        String code = "这是一段私人信息。只有登录才能显示";
        return new Result(ResultCode.SUCCESS,code);
    }

88c76b09c9c7403ca9e008bdbefd5f1c.png

不携带Token 打印结果:

845390cd1dd949d7855ea84876c9ca80.png

beae14d722224a13bd38180bcf6b83ed.png

Token 错误:

608030470fd44dc5ab9b5bb75666c851.png

3: 使用@PassToken() 放行请求 ,即不需要Token 也可登录

@PassToken()
    @PostMapping("/private/Test2")
    public Result info2(){
        String code = "这是一段普通信息。不登录也能显示";
        return new Result(ResultCode.SUCCESS,code);
    }

61d7ffc24da54258bac2006337893a12.png

源码地址如下:

SpringBoot 整合 jwt: 学习token的1111

目录
相关文章
|
3月前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
732 5
|
1月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
163 26
|
2月前
|
缓存 Java 数据库
SpringBoot缓存注解使用
Spring Boot 提供了一套方便的缓存注解,用于简化缓存管理。通过 `@Cacheable`、`@CachePut`、`@CacheEvict` 和 `@Caching` 等注解,开发者可以轻松地实现方法级别的缓存操作,从而提升应用的性能和响应速度。合理使用这些注解可以大大减少数据库的访问频率,优化系统性能。
214 89
|
6天前
|
JSON 前端开发 Java
Spring MVC常用的注解
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中 的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 @Controller:控制器的注解,表示是表现层,不能用用别的注解代替 @RestController : 组合注解 @Conntroller + @ResponseBody @GetMapping , @PostMapping , @Put
|
6天前
|
Java Spring
Spring Boot的核心注解是哪个?他由哪几个注解组成的?
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 : ● @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能; ● @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项 ● @ComponentScan:Spring组件扫描
|
8天前
|
Java 测试技术 Spring
SpringBoot+@Async注解一起用,速度提升
本文介绍了异步调用在高并发Web应用性能优化中的重要性,对比了同步与异步调用的区别。同步调用按顺序执行,每一步需等待上一步完成;而异步调用无需等待,可提升效率。通过Spring Boot示例,使用@Async注解实现异步任务,并借助Future对象处理异步回调,有效减少程序运行时间。
|
3月前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
209 73
|
5天前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
17 0
|
5天前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——拦截自定义异常
本文介绍了在实际项目中如何拦截自定义异常。首先,通过定义异常信息枚举类 `BusinessMsgEnum`,统一管理业务异常的代码和消息。接着,创建自定义业务异常类 `BusinessErrorException`,并在其构造方法中传入枚举类以实现异常信息的封装。最后,利用 `GlobalExceptionHandler` 拦截并处理自定义异常,返回标准的 JSON 响应格式。文章还提供了示例代码和测试方法,展示了全局异常处理在 Spring Boot 项目中的应用价值。
18 0
|
1月前
|
监控 Java Spring
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
73 16

热门文章

最新文章