使用jwt写过滤器流程

目录

1.pom依赖

2.工具类

3.登录生成jwt返回给前端,以后请求头中放入jwt

4.其余接口使用jwt中的payload信息

5.过滤器校验jwt的安全(有无篡改,是否失效,注意,并不能保证信息不泄露,这点应提前了解)

6.web.xml文件映射

7.测试方法


前言:

做一个老项目改造,将之前的mvc改为前后端分离的版本

想到之前写小程序时用的jwt就顺便也给session干掉换成jwt了

session和jwt的区别大家自己另行百度,我这就是做完整合下步骤,不会的可以参考下

 

1.pom依赖

<!--JSON Web Token Support,JWT工具-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2.工具类

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.impl.DefaultClaims;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Date;
import java.util.Random;

public class JwtUtils {
    //默认过期时间,单位秒
    public static final long DEFAULT_EXPIRE_TIME = 2 * 60 * 60;

    private static final String DEFAULT_SECRET="4dc25eeb75ba9ca1e4c504af3cb6259f" ;

    /**
     * 生成jwt字符串
     * @param expiration 有效时长,单位秒
     * @param secret 秘钥(盐)
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String generateJwt(String subjectId, long expiration, String secret) throws Exception {
        if(StringUtils.isBlank(secret)|| secret.length()< 8) {
            secret = DEFAULT_SECRET;
        }
        byte[] secretBytes = secret.getBytes("UTF-8");
        DefaultClaims claims = new DefaultClaims();claims.setSubject(subjectId);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate(expiration))
                .signWith(SignatureAlgorithm.HS256,secretBytes).compact();
    }

    /**
     * 生成jwt字符串
     * @param claims
     * @param expiration 有效时长,单位秒
     * @param secret 秘钥(盐)
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String generateJwt(Claims claims, long expiration, String secret) throws Exception {
        if(StringUtils.isBlank(secret)|| secret.length()< 8) {
            secret = DEFAULT_SECRET;
        }
        byte[] secretBytes = secret.getBytes("UTF-8");
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate(expiration))
                .signWith(SignatureAlgorithm.HS256,secretBytes).compact();
    }

    public static String getSubject(String jwt,String secret) throws Exception {
        return JwtUtils.getPayload(jwt,secret).getSubject();
    }

    public static Date getExpiration(String jwt,String secret) throws Exception {
        return JwtUtils.getPayload(jwt, secret).getExpiration();
    }

    /**
     * 获取jwt的payload
     * @param jwt
     * @param secret 秘钥(盐)
     * @return
     * @throws UnsupportedEncodingException
     */
    public static Claims getPayload(String jwt,String secret) throws ExpiredJwtException,
            MalformedJwtException, SignatureException, IllegalArgumentException, UnsupportedEncodingException {
        if(StringUtils.isBlank(secret)|| secret.length()< 8) {
            secret = DEFAULT_SECRET;
        }
        byte[] secretBytes = secret.getBytes("UTF-8");
        return (Claims)Jwts.parser().setSigningKey(secretBytes).parse(jwt).getBody();
    }

    public static Claims getPayloadWithoutCheck(String jwt) throws JsonProcessingException, UnsupportedEncodingException {
        String[] split = jwt.split("\\.");
        String body = new String(Base64.getDecoder().decode(split[1]), "UTF-8");
        return JSONObject.parseObject(body,DefaultClaims.class);
    }

    /**
     * 验证jwt 时效
     * @param claims
     * @return
     */
    public static boolean validateJwtExpire(Claims claims){
        Date date = claims.getExpiration();
        return new Date(System.currentTimeMillis()).before(date);
    }

    /**
     * 生成token的过期时间
     */
    private static Date generateExpirationDate(long expiration) {
        if(expiration<=0){
            expiration = DEFAULT_EXPIRE_TIME;
        }
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

}

3.登录生成jwt返回给前端,以后请求头中放入jwt

@POST
@Path("/login")
public ComResult login(@ModelAttribute User user) {
    try {
        //调用的是中台提供的登录判断接口,登录成功返回token,失败返回code不同
        RestResponse<LoginRespDto> login = memberCenterApi.login(user.getUsername(), user.getPassword());
        if (RestResponse.SUCC_CODE.equals(login.getResultCode())) {
            //加入jwt携带信息
            Claims claimsMap = new DefaultClaims();
            claimsMap.setSubject(login.getData().getToken());
            claimsMap.put("userId", user.getUsername());
            String jwt = "";
            try {
                jwt = JwtUtils.generateJwt(claimsMap, 1200, null);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            Map<String, Object> responseMap = new HashMap<>();
            responseMap.put("userId", user.getUsername());
            responseMap.put("auth", jwt);
            return ComResult.success("登录成功", responseMap);
        } else {
            return ComResult.failed(login.getResultMsg());
        }
    } catch (Exception e) {
        log.error("调用会员中台登录接口失败:{}", e.getMessage());
        log.error("调用会员中台登录接口失败param:{}", JSON.toJSONString(user));
        return ComResult.failed("调用会员中台登录接口失败");
    }
}

4.其余接口使用jwt中的payload信息

@GET
@Path("/logout")
public ComResult logout(@HeaderParam("auth") String auth) {
    String token = null;
    try {
        token = JwtUtils.getPayloadWithoutCheck(auth).getSubject();
    } catch (Exception e) {
        log.error("jwt解析异常:{}", e.getMessage());
        return ComResult.failed("jwt解析异常");
    }
    try {
        RestResponse<Void> logout = memberCenterApi.logout(token);
        if (RestResponse.SUCC_CODE.equals(logout.getResultCode())) {
            return ComResult.success(logout);
        } else {
            return ComResult.failed(logout.getResultMsg());
        }
    } catch (Exception e) {
        log.error("调用会员中台注销接口失败:{}", e.getMessage());
        log.error("调用会员中台注销接口失败param:{}", JSON.toJSONString(token));
        return ComResult.failed("调用会员中台注销接口失败");
    }
}

5.过滤器校验jwt的安全(有无篡改,是否失效,注意,并不能保证信息不泄露,这点应提前了解)

普通springMVC过滤器创建步骤:

继承Filter类,实现doFilter方法-->在web.xml文件中配置mapping

import com.alibaba.fastjson.JSON;
import com.lppz.product.web.common.ComResult;
import com.lppz.product.web.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class AuthFilter implements Filter {

    /**
     * 授权不通过
     */
    public static final String UNAUTHORIZED = "999";
    /**
     * 调用会员中台接口重试次数
     */
    public static final int RETRYTIME = 3;

    private String jwtSecret;
    /**
     * 过滤器开关
     */
    private final boolean enabled = false;

    @Override
    public void init(FilterConfig filterConfig) {
        jwtSecret = filterConfig.getInitParameter("jwt_secret");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //未开启,不需过滤,直接放行
        if (!enabled) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        //排除的链接
        String excludeStr = "/webresources/ui/member/login";
        String[] excludes = excludeStr.split(",");
        //排除的链接,不需过滤 直接放行
        if (handleExcludeUrl(req, excludes)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json");
        //获取jwt token 命名为auth,为了跟中台的token做区分
        String auth = req.getHeader("auth");
        log.info("获取到客户端携带的auth:{}", auth);
        if (StringUtils.isBlank(auth)) {
            log.info("获取到客户端携带的auth为空");
            resp.getWriter().println(JSON.toJSONString(ComResult.failed(UNAUTHORIZED,"获取到客户端携带的token为空",null)));
            return;
        }
        //校验jwt token 是否真实,是否超时
        Claims payload = null;
        try {
            payload = JwtUtils.getPayload(auth,jwtSecret);
        } catch (ExpiredJwtException e) {
            log.warn("jwt auth已过期:[{}]", auth);
            resp.getWriter().println(JSON.toJSONString(ComResult.failed(UNAUTHORIZED,"token已过期",null)));
            return;
        } catch (Exception e) {
            log.warn("jwt auth校验不通过:[{}]", auth);
            resp.getWriter().println(JSON.toJSONString(ComResult.failed(UNAUTHORIZED,"token校验不通过",null)));
            return;
        }
        //获取token信息
        Object userId = payload.get("userId");
        //校验通过,则解析jwt token 获取信息 设置到request中,放行
        servletRequest.setAttribute("userId", userId);
        log.debug("当前登录人是{}", userId);
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }

    private boolean handleExcludeUrl(HttpServletRequest req, String[] excludes) {
        if (excludes == null || excludes.length < 1) {
            return false;
        }
        String url = req.getRequestURI();
        for (String pattern : excludes) {
            if (pattern.equals(url)) {
                return true;
            }
        }
        return false;
    }
}

6.web.xml文件映射

<filter>
   <filter-name>AuthFilter</filter-name>
   <filter-class>***.***.***.web.filter.AuthFilter</filter-class>
   <init-param>
      <param-name>jwt_secret</param-name>
      <param-value>acc3.0jwt_secret</param-value>
   </init-param>
</filter>

<filter-mapping>
   <filter-name>AuthFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

7.测试方法

@GET
@Path("/test")
public ComResult test(@Context HttpServletRequest request) {
    String userId = (String)request.getAttribute("userId");
    return ComResult.success(userId);
}

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值