springboot整合jwt实现登录用户认证

在springboot项目中结合使用jwt框架对当前登录的用户进行认证,用户信息进行加密返回给前端token

jwt相关博文了解:

点击查看什么是jwt?

session与jwt不同的实现方式

具体实现

  • 创建一个springboot项目
  • 引入jwt核心依赖和相关基本依
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

        <!--引入 jwt对java实现的 依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.8</version>
        </dependency>
  • 创建一个jwt工具类 JwtTokenUtil
public class JwtTokenUtil {

    /**
     * jwt密匙
     */
    private String jwtSecret;
    /**
     * 默认过期时间
     */
    private Long defaultExpiredDate;

    public JwtTokenUtil(String jwtSecret, Long defaultExpiredDate) {
        this.jwtSecret = jwtSecret;
        this.defaultExpiredDate = defaultExpiredDate;
    }

    /**
     * 设置用户jwt对象数据并返回加密token
     * @param userId  用户id
     * @param claims 存储的参数map
     * @return
     */
    public String generateToken(String userId, Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + defaultExpiredDate * 1000L);
        Date createdDate = new Date();
        return claims == null ? Jwts.builder().setSubject(userId).setIssuedAt(createdDate).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, this.jwtSecret).compact() :
                Jwts.builder().setClaims(claims).setSubject(userId).setIssuedAt(createdDate).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, this.jwtSecret).compact();
    }

    /**
     * 通过token获取用户对象数据
     * @param token 查询token
     * @return
     */
    public Claims getClaimFromToken(String token) {
        return (Claims)Jwts.parser().setSigningKey(this.jwtSecret).parseClaimsJws(token).getBody();
    }

}

1.在实际业务中jwt私钥请妥善保管不要泄露了,不然容易被非法人员获取token并通过私钥进行破解,用户数据将不再安全。

2.在实际业务中jwt私钥(jwtSecret)默认过期时间(defaultExpiredDate),可定义在.properties.yml类型的配置文件中,并定义@ConfigurationProperties注解类进行映射对应,便于随时修改和维护。

  • 创建简单的用户信息实体类 LoginUser 
@Data
public class LoginUser {

    private Long id;

    private String name;

    private String pwd;

}
  •  创建登录用户上下文类,用于用户的相关信息操作类 LoginContext 
public class LoginContext {

    //自定义jwt私钥
    private static String jwtSecret = "remaindertime";
    //jwt过期时间(秒)
    private static Long  jwtATExpiredDate = 60L;
    private JwtTokenUtil jwtTokenUtil;
    private static LoginContext loginContext = null;

    //通过构造方法创建  jwtTokenUtil 对象
    public LoginContext(String jwtSecret,Long jwtATExpiredDate) {
        this.jwtTokenUtil = new JwtTokenUtil(jwtSecret, jwtATExpiredDate);
    }

    //构建 LoginContext 对象
    public static LoginContext me() {
            if(loginContext == null){
                loginContext = new LoginContext(jwtSecret,jwtATExpiredDate);
            }
        return loginContext;
    }

    /**
     * 登录成功后设置用户数据到jwt中
     * @param user 用户对象
     * @return 返回token
     */
    public String generateToken(LoginUser user) {
        HashMap<String, Object> claims = new HashMap();
        claims.put("user", user);
        return this.jwtTokenUtil.generateToken(user.getId().toString(), claims);
    }

    /**
     * 获取当前登录用户基本信息对象
     * @return
     */
    public LoginUser getLoginUserNoException() {
            String token = this.getCurrentUserTokenReal();
            if (token != null) {
                currentUser = this.getUserFromToken(token);
                return currentUser;
            } else {
                return null;
            }
    }

    /**
     * 通过token解析用户信息对象
     * @param token
     * @return
     */
    public LoginUser getUserFromToken(String token) {
        Claims claimFromToken = this.jwtTokenUtil.getClaimFromToken(token);
        Map mapUser = claimFromToken.get("user", Map.class);
        return  BeanUtil.mapToBean(mapUser, LoginUser.class, false);
    }


    /**
     * 获取当前请求下 请求头中的 Authorization 或者 请求参数中 token值
     * @return
     */
    public String getCurrentUserTokenReal() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String token;
        if (request != null) {
            String authToken = request.getHeader("Authorization");
            if (!StringUtils.isEmpty(authToken)) {
                return authToken;
            }
            token = request.getParameter("token");
            if (!StringUtils.isEmpty(token)) {
                return token;
            }
        }
        return null;
    }

}
  • 创建controller实现简单的登录和用户信息获取
    @RestController
    public class JwtController {
    
        /**
         * 模拟用户登录接口
         * @param userName 账号
         * @param pwd 密码
         * @return
         */
        @PostMapping(value = "/login")
        public String login( String userName, String pwd){
    
            //校验登录密码是否正确(略)
            //...
            //校验成功,保持用户数据到jwt中,并生成token返回给前端
            LoginUser loginUser = new LoginUser();
            loginUser.setId(1L);
            loginUser.setName(userName);
            String s = LoginContext.me().generateToken(loginUser);
            return s;
        }
    
        /**
         * 获取用户信息名称
         * @return
         */
        @GetMapping(value = "/getUserInfo")
        public String getUserInfo(){
            //通过用户工具类获取用户信息,
            LoginUser user = LoginContext.me().getLoginUserNoException();
            //用户未登录返回提示
            if(user == null){
                return "请登录";
            }
            return user.getName();
        }
    
    }

    测试

  • 模拟登录,返回 token
  •  模拟获取用户信息 将 token设置到请求头中

 :如果在完整的系统中,可把token存储在前端本地,每次请求是都携带该token,后端获取并进行用户登录校验

  • token 实现请求(前端获取不到用户信息,并且后端控制台JWT报错)

gtihub地址:前往github获取demo

补充小知识

jwt存在一个明显的弊端,就是用户生成的token不能手动删除,只有等设置的过期时间到了才会自动删除,所以在实际业务使用中,如果修改了用户信息,重新生成token ,但之前生成token不会消失,那么直接用原来的token也能通过。

所以需要结合redis来使用,redis存储token,用户更新信息后删除之前的,更新为当前最新token,当用户请求时,通过校验redis是否存在该请求头中的token,进而判断token是否有效


原创不易,多多一键三连呀!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

RemainderTime

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

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

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

打赏作者

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

抵扣说明:

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

余额充值