springboot3+vue3(四)登录接口逻辑(JWT)

登录校验逻辑

1、校验用户名是否存在     

2、校验密码是否正确   

3、返回JWT令牌

@PostMapping("/login")
    public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password)
    {
        //@Pattern(regexp = "^\\S{5,16}$") 参数校验 是否符合5-16位
        //查重用户
        User u = userService.findByUserName(username);
        if(u==null)
        {
            //用户名不存在
            return Result.error("用户名不存在!");
        }

        if(u.getPassword().equals(Md5Util.getMD5String(password)))
        {
            //返回jwt令牌
            String JWTToken = "JWTToken";
            return Result.success(JWTToken);
        }

        //密码错误
        return Result.error("密码错误!");


    }
login无JWT逻辑

运行结果:

 

 

 

 

调用JWT流程

1、添加JWT坐标依赖

<!--JWT坐标依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>
pom-jwt坐标依赖

2、测试生成JWT token代码

@Test
    public void testGenToken()
    {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("username","张三");

        //生成JWT代码
        String token = JWT.create()
                .withClaim("user",claims)//添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))//token过期时间 1秒*60*60*12=12小时
                .sign(Algorithm.HMAC256("joejoe"));

        System.out.println(token);
    }
create JWT token

 

3、JWT token 验证

@Test
    public void parseToken()
    {
        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +
                ".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuW8oOS4iSJ9LCJleHAiOjE3MDk2NTg2Nzl9" +
                ".RMXj3x4JTdcLkMuTDLVpY9V6VfgoNUyb5buzOK-kqEk";//运行testGenToken生成的token

        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("joejoe")).build(); //生成一个jwt的验证器 秘钥必须与生成jwt使用的秘钥一致
        DecodedJWT decodeJWT = jwtVerifier.verify(token);//验证token生成一个解析后的jwt对象  此处的token必须是一个有效的并且未过期的
        Map<String, Claim> claims = decodeJWT.getClaims();//获取载荷内容
        System.out.println(claims.get("user"));//输出载荷
    }
jwt校验

 

 

JWT集成到程序内

package com.example.bigevent.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import java.util.Date;
import java.util.Map;

public class JwtUtil {

    private static final String KEY = "itheima";
    
    //接收业务数据,生成token并返回
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims)
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
                .sign(Algorithm.HMAC256(KEY));
    }

    //接收token,验证token,并返回业务数据
    public static Map<String, Object> parseToken(String token) {
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }

}
JWT封装工具类

登录接口完善

@PostMapping("/login")
    public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password)
    {
        //@Pattern(regexp = "^\\S{5,16}$") 参数校验 是否符合5-16位
        //查重用户
        User u = userService.findByUserName(username);
        if(u==null)
        {
            //用户名不存在
            return Result.error("用户名不存在!");
        }

        if(u.getPassword().equals(Md5Util.getMD5String(password)))
        {
            //生成载荷
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",u.getId());
            claims.put("username",u.getUsername());

            //生成并返回jwt令牌
            String JWTToken = JwtUtil.genToken(claims);
            return Result.success(JWTToken);
        }

        //密码错误
        return Result.error("密码错误!");


    }
login完善JWT逻辑

 

其它接口访问前先去校验token是否合法,这里我们通过拦截器来实现

1、编写登录拦截器

@Component
//登录拦截器
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");
        try {
            Map<String,Object> claims = JwtUtil.parseToken(token);//验证token
            //放行
            return true;
        } catch (Exception e) {
            //http响应状态码为401
            response.setStatus(401);
            //不放行
            return false;
        }

    }
}
登录拦截器

 

 

2、注册拦截器,并配置不拦截 登录和注册接口

@Configuration//注入到IOC容器
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登录接口和注册接口不拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
    }
}
注册拦截器

 

到此拦截器配置完成,如果后续还有不需要拦截的接口,在excludePathPatterns后面继续追加接口即可,逗号分隔。

为了测试拦截器效果这里写一个简单的文章列表接口来校验

 

测试结果

 

登录获取token

 

 

 

 

 

 

 

 

相关接口:

获取当前登录人的用户详细信息(根据token获取当前登录人的详细信息)

在UserController内新增相关接口

@GetMapping("/userInfo")
    public Result<User> userInfo(@RequestHeader(name="Authorization") String token)
    {
        Map<String,Object> map = JwtUtil.parseToken(token);
        String username = (String) map.get("username");
        User u = userService.findByUserName(username);
        return Result.success(u);
    }
获取当前登录用户详细信息

运行发现

 

createTime和updateTime未返回值是因为数据库表内这两个字段为下划线命名法,与实体的驼峰命名法不一致。

 

解决方法:

1、在User实体类的password属性上加上 @JsonIgnore 注解 //让springmvc把当前对象转换成json字符串的时候,忽略password,最终的json字符串中就没有password这个属性了

2、添加驼峰命令和下划线命令的自动转换配置

mybatis:
  configuration:
    map-underscore-to-camel-case: true #开启驼峰命名和下划线命名的自动转换
yml内相关配置

 结果展示:

 

posted @ 2024-03-04 16:22  一介桃白白  阅读(530)  评论(0编辑  收藏  举报