JWT令牌以及登录拦截

1.登录校验—JWT令牌

**JWT:**JSON Web Token(JSON Web 令牌),令牌是用户的合法身份凭证(实际上是一个字符串)

官网:https://jwt.io/

  • JWT令牌实际上是一个包含了用户的某些信息的字符串,将原始的json数据格式进行了安全的封装。

在浏览器中发送登录请求后,后端要对前端发送的请求中的用户信息进行校验,如果校验成功,那就登录成功,后端会生成一个JWT令牌(存放着用户的信息如id、账号等)用来标识用户的身份,并将该令牌响应给前端,前端将这个令牌存储起来(可以存放在cookie中,也可以存放在其他的存储空间,比如localStorage中),在接下来的前端的每一次请求中都会携带着JWT令牌到后端,后端要对前端的每一次请求进行拦截,得到并校验前端的令牌的有效性,如果令牌是有效的,就说明用户已经执行了登录操作,直接放行进行请求的处理;否则就说明用户未执行有效操作,直接拒绝访问。

1.1JWT令牌的组成

JWT令牌由三部分(头、有效载荷、签名)组成,三个部分之间使用英文的点来分隔。

  • 第一部分:Header(头):记录签名算法、令牌类型等。例如:{“alg”:“HS256”,“type”:“JWT”}
  • 第二部分Payload(有效载荷):携带一些自定义的信息、默认信息。例如{“id”:“1”,“username”:“Tom”}
  • 第三部分Signature(签名):防止JWT被篡改、确保安全性。将header、payload和自定义的密钥,通过指定签名算法计算而来。篡改令牌中的任何一个字符,在对令牌进行解析时都会报错。

在生成JWT令牌时,会对JSON格式的数据进行一次base64编码,注意Base6是编码方式,而不是加密方式。(Base是一种基于64个可打印的字符来表示二进制数据的编码方式)

JWT令牌还可以指定过期时间,过期后该令牌就失效了。

1.2 JWT令牌的生成和校验

1.2.1 引入JWT依赖

JWT令牌使用要引入JWT令牌的依赖,直接在工具包中提供的API来完成JWT令牌的生成和校验

<!-- JWT依赖-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
1.2.2 创建JWT工具类
  • JWT工具类里面包含生成JWT令牌、解析JWT令牌的方法
public class JwtUtils {

    private static String signKey = "wenyin";//签名密钥为“wenyin”
    private static Long expire = 3600000L; //有效时间为1小时

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)//自定义信息(有效载荷)
                .signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
                .setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)//指定签名密钥
                .parseClaimsJws(jwt)//指定令牌Token
                .getBody();
        return claims;
    }
}
1.2.3 使用JWTUtils在登录成功之后生成JWT令牌
    @PostMapping("/login")
    public Result login(String username, String password){
        //根据用户名查询用户
        User user = userService.findByName(username);
        if(user == null) {
            return Result.error("用户名不存在或账号异常");
        }
        //使用md5对密码进行加密,与数据库中的已加密的密码进行比较
        if(Md5Util.getMD5String(password).equals(user.getPassword())) {
            //设置JWT令牌的有效载荷
            //claims指的是声明或声明的部分,它们是JWT包含的有效载荷的一部分。这些声明包含有关被认证主体的信息。
            Map<String,Object> cliams = new HashMap<>();
            cliams.put("id",user.getId());
            cliams.put("username", user.getUsername());
            String token = JwtUtil.genToken(cliams);
            return Result.success(token);
        }
        return Result.error("密码错误");
    }

2. 拦截器

拦截器的作用:

  • 拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码。

​ 自定义拦截器需要实现HandlerInterceptor接口,重写该接口的三个方法(这三个方法前加上了default关键字,表明这三个方法是接口的默认方法,这些方法带有具体的实现,意味着一个类实现了一个包含default方法的接口的时候,并不需要强制重写这些default方法),你可以根据自己的需要选择性地重写这些方法,而不是全部都要实现。

​ HandlerInterceptor接口是Spring MVC框架中的一个核心接口,主要用于实现AOP风格的拦截器功能。可以实现对HTTP请求的全面控制和定制处理,包括请求的预处理,请求后处理以及请求完全结束后的清理工作。

HandlerInterceptor接口源码:

public interface HandlerInterceptor {
    
    //preHandle(处理请求前)方法会在请求实际到达控制器(Controller)方法之前被调用,它允许你进行预处理操作,例如、登录拦截、权限验证、参数校验等,如果该方法返回true,则继续执行后继的处理器(如Controller方法),若返回false,则中断请求的进一步处理,并直接返回。
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    //postHandle(处理请求之后)方法在请求处理完毕且视图渲染之前执行(即Controller方法已经执行完毕但响应尚未发送给客户端),在此方法,可以访问或修改模型数据(ModelAndView对象),或者对视图做出一些格外的处理工作。
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    //afterCompletion(完成请求处理之后)方法在整个请求处理完毕之后,包括视图渲染完成之后调用,它可以用于资源清理、记录日志等工作。即使在preHandle()阶段就阻止了请求的处理,afterCompletion()依然会被调用。
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

2.1 自定义登录拦截器

自定义登录拦截器需要实现HandlerInterceptor接口,并重写其方法

​ 通过拦截器来拦截前端发起的请求,将登录校验的逻辑全部编写在拦截器当中。在校验的过程当中,如发现用户登录了(携带JWT令牌且是合法令牌),就可以直接放行,去访问spring当中的资源。如果校验时发现并没有登录或是非法令牌,就可以直接给前端响应未登录的错误信息。

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        令牌验证,从前端的请求头里面得到Authorization中的jwt令牌判断是否登录成功
        String token = request.getHeader("Authorization");

        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            return true;
        } catch (Exception e) {
            /**
             * 设置响应状态码为401,表示未登录
             */
            response.setStatus(401);
            return false;
        }
    }
}

自定义拦截器之后还需要注册配置拦截器

注册配置拦截器:实现WebMvcConfigurer接口,并重写addInterceptors方法,注册自定义拦截器对象,定义需要拦截的资源和不需要拦截的资源。

@Configuration  
public class WebConfig implements WebMvcConfigurer {
    //拦截器对象
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       //注册自定义拦截器对象
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login");
//          "/**",表示拦截所有资源,`excludePathPatterns("不拦截路径")`指定哪些资源不需要拦截。
    }
}

JWT(JSON Web Token)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。一般来说,JWT 用于认证和授权,其主要应用场景为 API 接口鉴权。生成 JWT 的流程可以通过拦截器来实现,以下是一个简单的生成 JWT 令牌拦截器实现过程: 1. 创建一个 JWT 工具类,用于生成和解析 JWT 令牌。 2. 创建一个 JWT 拦截器类,该类需要实现 HandlerInterceptor 接口。 3. 在 preHandle 方法中,判断当前请求是否需要生成 JWT 令牌,如果需要,则使用 JWT 工具类生成令牌,并将其存储在请求头中。 4. 在 postHandle 方法中,将生成的 JWT 令牌返回给客户端。 5. 在 afterCompletion 方法中,清除请求头中的 JWT 令牌。 以下是一个简单的生成 JWT 令牌拦截器示例: ``` public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断当前请求是否需要生成 JWT 令牌 if (request.getRequestURI().startsWith("/api/")) { // 获取用户信息 User user = (User) request.getSession().getAttribute("user"); // 判断用户信息是否为空 if (user != null) { // 使用 JWT 工具类生成令牌 String token = JwtUtils.generateToken(user); // 将生成的 JWT 令牌存储在请求头中 response.setHeader("Authorization", token); } else { // 用户信息为空,返回未授权状态码 response.setStatus(HttpStatus.UNAUTHORIZED.value()); return false; } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 将生成的 JWT 令牌返回给客户端 response.setHeader("Authorization", response.getHeader("Authorization")); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 清除请求头中的 JWT 令牌 response.setHeader("Authorization", null); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻音麻花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值