SpringBoot集成JWT

一、 背景

项目需要,自己编写登录和身份校验,于是采用了JWT的方式。

二、实现步骤

2.1 引入JWT组件
 <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version> <!-- 使用时请检查最新版本 -->
        </dependency>
2.2 编写JWT工具类


 
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

/**
 * @author *****
 * @description JWT 工具类
 * @date 2024年04月08日 15:45
 */
public class JwtTokenUtil {

    /**
     * 生成token
     * @param token存入的值,包括username userfullname  手机号 代理商id  代理商名称
     * @return
     */
    public static String generateToken(String userToken) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + Constants.TOKEN_EXPIRATION);

        return Jwts.builder()
                .setSubject(userToken)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, Constants.TOKEN_SECRET)
                .compact();
    }

    /**
     * 根据token获得Claims
     * @param username
     * @return
     */
    public static Claims getClaimsFromToken(String token) {
        try {
            return Jwts.parser().setSigningKey(Constants.TOKEN_SECRET).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据token获得用户
     * @param username
     * @return
     */
    public  static String getUsernameFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.getSubject() : null;
    }


    /**
     * 校验token是否有效
     * @param token
     * @param username
     * @return
     */
    public static boolean validateToken(String token) {
        final String usernameFromToken = getUsernameFromToken(token);
        return (usernameFromToken != null  && !isTokenExpired(token));
    }


    /**
     * token 是否超时
     * @param token
     * @return
     */
    private static boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * token 得到token的超时时间
     * @param token
     * @return
     */
    private static Date getExpirationDateFromToken(String token) {
        final Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

}

2.3 用户登录生成token
 public ResultBO<String> userLogin(SysUserBO sysUserBO)
    {
        ResultBO<String> resultBO = new   ResultBO<String>();
        if(StringUtil.isNullOrEmpty(sysUserBO.getUserName()) )
        {
            resultBO.setCode(CommonResult.USER_IS_NOT_NULL.getCode());
            resultBO.setSuccess(false);
            resultBO.setMessage("登录失败:请输入用户名");
            return  resultBO;
        }

        if(StringUtil.isNullOrEmpty(sysUserBO.getUserPassWord()) )
        {
            resultBO.setCode(CommonResult.USER_IS_NOT_NULL.getCode());
            resultBO.setSuccess(false);
            resultBO.setMessage("登录失败:请输入密码");
            return  resultBO;
        }

       // 密码规则:用户账号+用户密码+固定字符串 然后用AES加密
        String passWord = sysUserBO.getUserName()+sysUserBO.getUserPassWord()+ Constants.PASS_WORD_SECRET;
        passWord=AesUtil.encrypt(passWord);
        SysUserDO  sysUserDO = new   SysUserDO();
        sysUserDO = ModelMapperUtil.map(sysUserBO,SysUserDO.class);
        sysUserDO.setUserPassWord(passWord);
        List<SysUserDO> sysUserDOS = sysUserDao.selectUserList(sysUserDO);
        if(sysUserDOS!=null && sysUserDOS.size()>0 )
        {
            // 查询到了用户
            // 登录成功创建token 将用户相关关键的字段都放入到token里面去
            TokenUser tokenUser = new TokenUser();
            tokenUser.setCenterUserId(sysUserDOS.get(0).getCenterUserId());
            tokenUser.setUserFullName(sysUserDOS.get(0).getUserFullName());
            tokenUser.setId(sysUserDOS.get(0).getId());
            tokenUser.setUserName(sysUserDOS.get(0).getUserName());
            tokenUser.setAgentId(sysUserDOS.get(0).getAgentId());
            tokenUser.setAgentName(sysUserDOS.get(0).getAgentName());
            tokenUser.setPhoneNumber(sysUserDOS.get(0).getPhoneNumber());

            String tokenUserDOStr = FastJsonUtil.toJsonString(tokenUser);
            String token =  JwtTokenUtil.generateToken(tokenUserDOStr); // sysUserDOS.get(0).getUserName()

          resultBO.setCode(CommonResult.SUCCESS.getCode());
          resultBO.setSuccess(true);
          resultBO.setMessage("登录成功");
          resultBO.setData(token);
        }
        else
        {
            // 查询不到数据
            // 登录失败
            resultBO.setCode(CommonResult.DATA_NOT_EXISTS_ERROR.getCode());
            resultBO.setSuccess(false);
            resultBO.setMessage("登录失败:账号或密码错误");
        }
        return  resultBO;
    }
2.4 编写拦截器校验token
 

 
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author ****
 * @description 自定义拦截器
 * @date 2024年04月08日 17:05
 */

@Component
public class MyInterceptor implements HandlerInterceptor {

    /**
     * 请求头
     */
    private static final String HEADER_AUTH = "token";


    /**
     * 拦截过滤方法
     * @param request
     * @param response
     * @param handler
     * @return
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        response.setContentType("application/json; charset=utf-8");
        String prop = request.getRequestURI().substring(request.getContextPath().length());
        String url =  prop;
        // 登录和注册等请求不需要令牌
        // 安全连接,无需拦截配置 一般开放登录方法
        if (prop.contains("/login/") || prop.contains("/syncUser") ) {
            return true;
        }
        // System.out.println("***********没有被放行的请求*************");
        // 从请求头里面读取token
        String token = request.getHeader(HEADER_AUTH);
        if (token == null) {
            throw new RuntimeException("请求失败,令牌为空");
        }
        System.out.println(token);

        // 解析令牌
        boolean validateToken = JwtTokenUtil.validateToken(token);
        if(!validateToken)
        {
            throw new RuntimeException("请求失败,无效的令牌");
        }
        else
        {
            try
            {
                // 如果是有效的,则解析token里面的user信息提供给接口使用
                String tokenStr = JwtTokenUtil.getUsernameFromToken(token);
                TokenUser tokenUser = FastJsonUtil.toObj(tokenStr,TokenUser.class);
                ContextHolder.setTokenUser(tokenUser);
                // 将用户信息添加到请求属性中
                // request.setAttribute("currentUser", tokenUser);
                return  true;
            }catch(Exception ex)
            {
                throw new RuntimeException("请求失败,无效的令牌");
            }
        }
    }
}

2.5 使用ContextHolder给接口调用获取当前登陆人


/**
 * @author ****
 * @description token解析用户信息Context类
 * @date 2024年04月09日 10:59
 */
public class ContextHolder {
    public static ThreadLocal<TokenUser> context = new ThreadLocal<>();

    public static void setTokenUser(TokenUser tokenUserDO) {
        context.set(tokenUserDO);
    }

    public static TokenUser getTokenUser() {
        return context.get();
    }

    public static void shutdown() {
        context.remove();
    }

}

2.6 注册拦截器,注意文件放置的位置要跟启动类同一层,这样才能扫描到



import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

/**
 * @author ***8
 * @description 自定义拦截器注册
 * @date 2024年04月08日 17:11
 */

@Configuration
public class InterceptorConfig  implements WebMvcConfigurer {

    @Resource
    private MyInterceptor loginInterceptor;

    @Override
    public void addInterceptors (InterceptorRegistry registry) {
        //注册LoginInterceptor拦截器
        registry.addInterceptor(loginInterceptor);
    }

}

2.7 TokenUser类
@Data
public class TokenUser {

    /**
     * 用户id
     */
    private Long id;

    /**
     * 用户名(登录账号名)
     */
    private String userName;

    /**
     * 代理商id
     */
    private String agentId;

    /**
     * 代理商名称
     */
    private String agentName;

    /**
     * 用户全名
     */
    private String userFullName;

    /**
     * 手机号
     */
    private String phoneNumber;

    /**
     * 中心系统 userid
     */
    private String centerUserId;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

代码写到35岁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值