Jwt,过滤器,拦截器

70 阅读3分钟

Jwt,过滤器,拦截器

JWT

JWT JSON Web Token,是一种用户身份识别的令牌技术。用于解决web开发中身份识别问题。

JWT主要由三部分组成:header头,body 载荷,Signature签名

header:主要存放令牌的签名算法和类型

body:存放一些数据,比如用户的身份信息

signature:header+body+密钥通过签名算法生成的签名字符串,用于验证身份信息,和权限校验.

要使用jwt首先要引入对应的依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
public class JwtDemo {
    public static void main(String[] args) throws InterruptedException {
        //1. 生成JWT令牌
        //1.1 准备载荷信息,即用户的身份信息
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", 1);
        claims.put("username", "tom");
        //1.2 生成JWT令牌
        String token = Jwts.builder()
                //把载荷内容设置到JWT令牌里
                .setClaims(claims)
                //设置令牌的过期时间。这里设置有效期为:截止到当前时间+1000毫秒,即有效期只有1秒(可以根据实际情况自定义有效期)
                .setExpiration(new Date(System.currentTimeMillis() + 1000))
                //设置令牌的密钥。在将来解析令牌时,根据密钥校验令牌的签名,防止令牌被篡改
                .signWith(SignatureAlgorithm.HS256, "itheima")
                //生成令牌
                .compact();
        System.out.println("token =" + token);


        //2. 校验与解析令牌:如果令牌过期,会抛出异常;如果令牌被篡改,会抛出异常;如果一切正常,会得到令牌里的载荷内容
        Claims claimsRes = Jwts.parser()
                //设置密钥。用于稍后的令牌签名校验,判断令牌是否被篡改了。如果令牌被篡改,会抛出异常
                .setSigningKey("itheima")
                //校验并解析令牌。如果令牌被篡改或已过期,会抛出异常
                .parseClaimsJws(token)
                //获取令牌载荷内容
                .getBody();
        System.out.println(claimsRes);
    }
}

一般,我们会在登录的接口中设置jwt令牌,通过定义一个claims对象,调用JwtUtil类下的createJWT()方法来创建出一个token字段

    /**
     * 员工登录
     */
    @Override
    public Result<EmployeeLoginVO> login(EmployeeLoginDTO employeeLoginDTO) {
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();
        //校验参数
        if (StringUtils.isAnyBlank(username, password)) {
            //账号密码错误
            throw new ParameterIsNullException(MessageConstant.PARAMETER_IS_NULL);
        }

        //1、根据用户名查询数据库中的数据
        Employee employee = employeeMapper.getByUsername(username); //

        //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
        if (employee == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        //密码比对

        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(employee.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (StatusConstant.DISABLE.equals(employee.getStatus())) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }
        //3、返回EmployeeLoginVO实体对象
        //登录成功后,生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);
        EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
                .id(employee.getId())
                .userName(employee.getUsername())
                .name(employee.getName())
                .token(token)
                .build();
        return Result.success(employeeLoginVO);
    }

过滤器Filter

过滤器Filter是基于Servlet规范的,对所有请求/响应进行全局处理,一般通过实现Filter接口,然后重写doFilter()方法来实现业务需求.

Filter是 JavaEE的技术,doFilter()方法总共有三个参数:request response chain

request 代表请求的Request对象,在接收数据时一般会强转成HttpServletRequest对象来使用

response 代表Response 响应对象

chain 代表过滤器链对象,调用doFilter表示放行

Filter一般还要搭配@WebFilter注解来设置拦截请求的范围

  • @WebFilter("拦截范围")
public class AuthFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if (httpRequest.getSession().getAttribute("user") == null) {
            ((HttpServletResponse) response).sendRedirect("/login");
            return;
        }
        chain.doFilter(request, response);
    }
}

拦截器

拦截器是由SpringMVC框架提供的技术,能够针对特定请求(如Controller方法)进行拦截

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (request.getSession().getAttribute("user") == null) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "未登录");
            return false; // 中断请求
        }
        return true; // 继续执行
    }
}

在使用拦截器时,一般需要在WebConfig 类中配置拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/api/**") // 拦截路径
                .excludePathPatterns("/public/**"); // 排除路径
    }
}