【SpringBoot】实战-开发接口-用户-登录
登录
界面
接口文档
逻辑
代码
@PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{5,16}$")String username,@Pattern(regexp = "^\\S{5,16}$")String password){//根据用户查询userUser user = userService.findByUsername(username);//判断是否查到if (user != null){//判断密码是否正确if (Md5Util.checkPassword(password,user.getPassword())){return Result.success();}else {return Result.error("登录失败:密码错误");}}else {return Result.error("登录失败:用户不存在");}}
登录认证
在没有登录的情况不能访问Article的内容,所以需要验证登录的状态
没有登录就可以访问,在访问list接口前,就需要对登录的状态进行验证
借助令牌可以解决以上访问的问题
令牌就是一段字符串
令牌要求
- 承载业务数据,减少后续请求查询数据库的次数
- 放篡改,保证信息的合法性和有效性
JWT令牌
简介
全称:json web token(https://jwt.io/)
定义了一种简洁的、自包含的格式,用于通信双方以json数据格式安全的传输信息
组成:
- 第一部分:header(头),记录令牌类型,签名算法等。列如{“alg”:“HS256”,“type”:“JWT”} alg:算法
- 第二部分:Payload(有效载荷、不要存放私密数据),携带一些自定义信息。默认信息等。例如{“id”:“1”,“username”:“tom”} 使用Base64(编码方式/公开)转换
- 第三部分:Signature(签名),防止Token被篡改,确保安全性。将header,payload,加入指定秘钥(通过头部算法alg来指定),通过指定签名算法计算而来
令牌的生成
添加依赖
<!-- JWT令牌--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency><!-- 单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency>
测试代码
package com.zwh;import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.junit.jupiter.api.Test;import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class JwtTest {@Testpublic void testGen(){Map<String,Object> claims = new HashMap<>();claims.put("id","1");claims.put("username","张三");String token = JWT.create().withClaim("user",claims)//添加载荷.withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))//添加过期时间.sign(Algorithm.HMAC256("zwh"));//签名(指定算法,配置秘钥)System.out.println(token);}
}
运行
令牌的验证
@Testvoid parseToken(){String token ="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiMSIsInVzZXJuYW1lIjoi5byg5LiJIn0sImV4cCI6MTc1MjcxMzU5N30.VcdVoQOieNVvE1C8wSb2COqiVTNtIW80ahFJ6ZCzURU";JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("zwh")).build();DecodedJWT decodedJWT = jwtVerifier.verify(token);Map<String, Claim> claims = decodedJWT.getClaims();System.out.println(claims.get("user"));}
注意事项
- JWT验证时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的
- 如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法
设置令牌
修改登陆代码
@PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{5,16}$")String username,@Pattern(regexp = "^\\S{5,16}$")String password){//根据用户查询userUser user = userService.findByUsername(username);//判断是否查到if (user != null){//判断密码是否正确if (Md5Util.checkPassword(password,user.getPassword())){Map<String, Object> map = new HashMap<>();map.put("username",user.getUsername());map.put("id",user.getId());String token = JwtUtil.genToken(map);return Result.success(token);}else {return Result.error("登录失败:密码错误");}}else {return Result.error("登录失败:用户不存在");}}
测试
验证令牌
@RestController
@RequestMapping("/article")
public class ArticleController {@GetMapping("/list")public Result<String> list(@RequestHeader(name = "Authorization") String token, HttpServletResponse response){//验证tokentry {Map<String,Object> claims=JwtUtil.parseToken(token);return Result.success("所有的文章数据。。。。");} catch (Exception e) {//http响应码为401response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);return Result.error("未登录");}}
}
拦截器
多处用到令牌验证
拦截器 :多个接口有同样的操作需要完成
package com.zwh.interceptors;import com.zwh.utils.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import java.util.Map;@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//令牌验证String token = request.getHeader("Authorization");try {Map<String,Object> claims = JwtUtil.parseToken(token);return true;//放行} catch (Exception e) {response.setStatus(401);return false;//不放行}}
}
package com.zwh.config;import com.zwh.interceptors.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//登录和注册接口不拦截registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");}
}