• springboot+jwt做登录鉴权(附完整代码)



    前言

    提示:这里可以添加本文要记录的大概内容:


    一、jwt做登录鉴权

    1.1 写出jwt 生成token 的工具类

    1.1.1 编写获取token工具类方法(getToken() )

    思路:
    一、首先考虑要接收的参数。要知道用户的ID或者用户名、角色等。因此这里把这三个属性封装到一个AuthInfo对象中。还要传入过期时间 和加密字符串信息。

    @Data
    public class AuthInfo {
        private Long UserId;
        private String userName;
        private String roles;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public static String getToken(AuthInfo authInfo, Date expireDate, String secret){
    return "";
    }
    
    • 1
    • 2
    • 3

    二、 进入方法时,首先判断参数是否为空,这里我们可以使用谷歌的包:com.google.common.base.Preconditions;里面有对应的API可以非常方便的做验证。
    代码:

    //做验证
            Preconditions.checkArgument(authInfo != null,"加密内容不能为null");
            Preconditions.checkArgument(expireDate != null,"过期时间异常");
            Preconditions.checkArgument(secret != null,"加密密码不能为null");
    
    • 1
    • 2
    • 3
    • 4

    三、使用JWT的Api调用方法,将Header和签名等参数赋值。

    Map<String, Object> map = new HashMap<>();
    // 固定格式
           map.put("alg", "HS256");
           map.put("typ", "JWT");
    
           String token = null;//签名
           try {
               token = JWT.create()
                       .withHeader(map)//头
                       // 参数
                       .withClaim(USER_ID,authInfo.getUserId())
                       .withClaim(USER_NAME,authInfo.getUserName())
                       .withClaim(USER_ROLES,authInfo.getRoles())
                       .withIssuedAt(new Date())//签名时间
                       .withExpiresAt(expireDate)//过期时间
                       .sign(Algorithm.HMAC256(secret));
           } catch (IllegalArgumentException e) {
               e.printStackTrace();
           } catch (JWTCreationException e) {
               e.printStackTrace();
           }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    四、返回token 字符串,下面是完整代码:

    package com.tzw.gene.utils;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTCreationException;
    import com.auth0.jwt.interfaces.Claim;
    import com.auth0.jwt.interfaces.DecodedJWT;
    import com.auth0.jwt.interfaces.JWTVerifier;
    import com.google.common.base.Preconditions;
    import com.tzw.gene.auth.AuthInfo;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     *
     * @author tzw
     * @version 1.0
     */
    public class JwtUtil {
        public static String USER_ID = "userId";
        public static String USER_NAME = "userName";
        public static String USER_ROLES = "roles";
    
        /**
         * 生成token
         * @param authInfo
         * @param expireDate
         * @param secret
         * @return
         */
        public static String getToken(AuthInfo authInfo, Date expireDate, String secret){
            Preconditions.checkArgument(authInfo != null,"加密内容不能为null");
            Preconditions.checkArgument(expireDate != null,"过期时间异常");
            Preconditions.checkArgument(secret != null,"加密密码不能为null");
    
            Map<String, Object> map = new HashMap<>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
    
            String token = null;//签名
            try {
                token = JWT.create()
                        .withHeader(map)//头
                        .withClaim(USER_ID,authInfo.getUserId())
                        .withClaim(USER_NAME,authInfo.getUserName())
                        .withClaim(USER_ROLES,authInfo.getRoles())
                        .withIssuedAt(new Date())//签名时间
                        .withExpiresAt(expireDate)//过期时间
                        .sign(Algorithm.HMAC256(secret));
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (JWTCreationException e) {
                e.printStackTrace();
            }
            return token;
        }
    
        /**
         * 验证 token正确性 并且返回authInfo对象
         * @param token
         * @param secret
         * @return
         * @throws Exception
         */
        public static AuthInfo verifyToken(String token,String secret)throws Exception{
            JWTVerifier verifier = null;
            try {
                verifier = JWT.require(Algorithm.HMAC256(secret)).build();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
            DecodedJWT jwt = null;
            try {
                jwt = verifier.verify(token);
            }catch (Exception e){
                // todo 统一异常处理
                throw new RuntimeException("凭证已过期,请重新登录");
            }
            AuthInfo authInfo = new AuthInfo();
            authInfo.setUserId(jwt.getClaim(USER_ID).asLong());
            authInfo.setUserName(jwt.getClaim(USER_NAME).asString());
            authInfo.setRoles(jwt.getClaim(USER_ROLES).asString());
    
            return authInfo;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    1.2 写出jwt 验证token 并且能够逆向转换成我们加密使用的对象(verifyToken() )

    验证 token正确性 并且返回AuthInfo对象
    思路:
    一、同样的,我们还是先考虑参数,很明显我们需要传入token字符串和一个密文(secret)

    二、然后用JWT.require(Algorithm.HMAC256(secret)).build()赋值给JWTVerifier对象,这时会验证密文的正确性,如果正确则会得到JWTVerifier对象。
    三、然后再通过JWTVerifier验证token是否过期。没有过期我们再得到AuthInfo(把AuthInfo从JWTVerifier对象解析出来最后返回。)
    代码如下:

        /**
         * 验证 token正确性 并且返回authInfo对象
         * @param token
         * @param secret
         * @return
         * @throws Exception
         */
        public static AuthInfo verifyToken(String token,String secret)throws Exception{
            JWTVerifier verifier = null;
            try {
                verifier = JWT.require(Algorithm.HMAC256(secret)).build();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
            DecodedJWT jwt = null;
            try {
            //验证token是否过期
                jwt = verifier.verify(token);
            }catch (Exception e){
                // todo 统一异常处理
                throw new RuntimeException("凭证已过期,请重新登录");
            }
            //下面得到AuthInfo对象
            AuthInfo authInfo = new AuthInfo();
            authInfo.setUserId(jwt.getClaim(USER_ID).asLong());
            authInfo.setUserName(jwt.getClaim(USER_NAME).asString());
            authInfo.setRoles(jwt.getClaim(USER_ROLES).asString());
    //返回authinfo对象
            return authInfo;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    写一个main方法测试

        public static void main(String[] args) {
            AuthInfo authInfo = new AuthInfo();
            authInfo.setUserId(1L);
            authInfo.setUserName("张三");
            authInfo.setRoles("管理员");
            String token = getToken(authInfo, new Date(), "123456");
            System.out.println(token);
            AuthInfo verifyToken = null;
            try {
                verifyToken = verifyToken(token, "123456");
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    1.3 登录接口中调用JwtUtil生成token 并且返回给前端

    service层代码:

    package com.tzw.gene.service.impl;
    import com.tzw.gene.auth.AuthInfo;
    import com.tzw.gene.entity.User;
    import com.tzw.gene.mapper.UserMapper;
    import com.tzw.gene.resp.LoginResp;
    import com.tzw.gene.resp.UserResp;
    import com.tzw.gene.service.IUserService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.tzw.gene.utils.JwtUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    
    /**
     * 

    * 服务实现类 *

    * * @author student_tzw * @since 2022-09-05 */
    @Service public class UserServiceImpl implements IUserService { @Autowired UserMapper mapper; private static final String SECRET="123456"; private static final Integer EXPIRED =24*3*60*60*1000;//3天(小时为单位) @Override public LoginResp login(String accountId, String password) { LoginResp loginResp = new LoginResp(); UserResp userResp = mapper.login(accountId,password); if (userResp == null){ loginResp.setSuccess(false); loginResp.setMsg("账号或密码不存在"); return loginResp; } //jwt生成token todo(已完成) AuthInfo authInfo = new AuthInfo(); authInfo.setUserId(userResp.getId()); authInfo.setUserName(userResp.getRealName()); authInfo.setRoles("admin,user");//todo 角色没有加进来 Date date = new Date(new Date().getTime()+ EXPIRED); String token = JwtUtil.getToken(authInfo, date, SECRET); userResp.setToken(token); loginResp.setData(userResp); return loginResp; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    service接口:

    package com.tzw.gene.service;
    
    import com.tzw.gene.entity.User;
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.tzw.gene.resp.LoginResp;
    
    /**
     * 

    * 服务类 *

    * * @author student_tzw * @since 2022-09-05 */
    public interface IUserService{ public LoginResp login(String accountId,String password); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    entity(实体层):(含Swagger)

    package com.tzw.gene.entity;
    
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import java.io.Serializable;
    import java.time.LocalDateTime;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.Getter;
    import lombok.Setter;
    
    /**
     * 

    * *

    * * @author student_tzw * @since 2022-09-05 */
    @Data @TableName("tb_user") @ApiModel(value = "User对象", description = "") public class User implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty("表的字段id")//swagger @TableId(value = "id", type = IdType.AUTO) private Long id; @ApiModelProperty("公司部门id ") private String deptId; @ApiModelProperty("用户姓名") private String realName; @ApiModelProperty("登录账号") private Long accountId; @ApiModelProperty("登录密码") private String password; @ApiModelProperty("邮箱地址") private String email; @ApiModelProperty("手机号") private String userPhone; @ApiModelProperty("创建时间") private LocalDateTime createTime; @ApiModelProperty("创建人") private String createUser; @ApiModelProperty("更新人") private String updateUser; @ApiModelProperty("更新时间") private LocalDateTime updateTime; @ApiModelProperty("状态") private String status; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    mapper:

    @Repository
    public interface UserMapper extends BaseMapper<User> {
    
        UserResp login(@Param("accountId") String accountId,@Param("password") String password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    返回对象:

    package com.tzw.gene.resp;
    
    import lombok.Data;
    
    /**
     * @author tzw
     * @version 1.0
     */
    @Data
    public class UserResp {
        private Long id;
    
        private String realName;
    
        private String deptId;
    
        private String phone;
    
        private String token;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    总结

  • 相关阅读:
    机器学习(14)---逻辑回归(含手写公式、推导过程和手写例题)
    如何使用Pritunl搭建OpenVPN服务器,实现远程连接【内网穿透】
    C语言每日一题(27)链表中倒数第k个结点
    SpringBoot_第六章(知识点总结)
    浅析 Vue3 响应式原理
    文献速递:深度学习乳腺癌诊断---基于深度学习的图像分析预测乳腺癌中H&E染色组织病理学图像的PD-L1状态
    Python学习笔记第五天(Number)
    RabbitMQ学习01
    java Collection和Map接口的区别
    Linux | 查看系统服务的方法的不完全总结
  • 原文地址:https://blog.csdn.net/qq_45821255/article/details/126731932