开发之前我们先看一下接口文档的要求:
开发思路:
开发实操:
因为我们之前开发注册的时候,就有了一些相关的操作,所以在这里我们只需要定义登录的controller即可:
//用户登录@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$")String username,@Pattern(regexp = "^\\S{5,16}$") String password) {//根据用户名查询用户User loginUser = userService.findUserByUsername(username);//判断用户是否存在if(loginUser == null){return Result.error("用户不存在");}//判断密码是否正确//因为之前是加密后存储的密码,所以我们也应该加密后再判断是否相同if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){//登录成功return Result.success("jwt token 令牌");}return Result.error("密码错误");}
测试:
我们将密码打错:
我们将密码打对:
认证登录【重点】:
为什么会有登录认证呢?
因为你登录用户之后会有很多的对应的操作接口,那么你不登录就无法使用到这些接口,所以,我们就会有“登录认证”,首先我们会借助令牌这个东西去校验我们的登录是否合理.....
令牌:
令牌是什么:
令牌的作用:
意思就是通过令牌才能够去访问登陆后的所有资源
JWT令牌:
我们这里使用JWT令牌(由“头”、“有效载荷”、“签名”)
JWT令牌具体有生成步骤和验证步骤:
生成令牌:
引入坐标:
<!--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></dependency>
测试类中测试:
package org.huangyingyuan;import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;//测试生成的JWT令牌
public class JwtTest {@Testpublic void test() {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))//设置过期时间(为12小时).sign(Algorithm.HMAC256("huangyingyuan"));//指定算法,配置秘钥System.out.println(token);}
}
测试结果为:
验证令牌:
在测试类中测试:
//验证jwt令牌@Testpublic void testParse(){//定义字符串token,模拟用户传过来的tokenString token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuW8oOS4iSJ9LCJleHAiOjE3NDMzNTc5NTB9" +".ipTTySrl3HwtkmcqUfMyp_os_M9cJIqa2kG01qNPYxo";JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("huangyingyuan")).build(); //构建验证器DecodedJWT decodedJWT = jwtVerifier.verify(token); //验证tokenMap<String, Claim>claims=decodedJWT.getClaims(); //获取载荷System.out.println(claims.get("user"));}
测试的结果如下:
几种测试失败的可能:
1.篡改了头部和载荷部分的数据,那么验证失败
2.密钥改了,验证失败
3.token设置的时间过期
正片开始:
生成JWT令牌:
1.导入Jwt的Util的工具类
省略
2.在controller类下去生成token,返回数据
//用户登录@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$")String username,@Pattern(regexp = "^\\S{5,16}$") String password) {//根据用户名查询用户User loginUser = userService.findUserByUsername(username);//判断用户是否存在if(loginUser == null){return Result.error("用户不存在");}//判断密码是否正确//因为之前是加密后存储的密码,所以我们也应该加密后再判断是否相同if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){//生成token(JWT令牌)Map<String, Object>claims=new HashMap<String, Object>();claims.put("id",loginUser.getId());claims.put("username",loginUser.getUsername());JwtUtil.genToken(claims);String token = JwtUtil.genToken(claims);//登录成功return Result.success(token);}return Result.error("密码错误");}
3.测试
验证JWT令牌:
我们先看一下接口文档的要求:
需要在请求头获取令牌,并定义了请求头名的是什么
若错误,定义响应码为401
拦截器:
设置拦截器后的登录验证流程:
注意!
1.@RequestHeader("Authorization")设置请求头
2.传入HttpServletResponse参数,提供响应码
package org.huangyingyuan.controller;import jakarta.servlet.http.HttpServletResponse;
import org.huangyingyuan.pojo.Result;
import org.huangyingyuan.utils.JwtUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;//模拟在用户登陆后才能使用的功能(在学习JWT令牌的作用)
@RestController
@RequestMapping("/article")
public class ArticleController {@GetMapping("/list")public Result<String> list(@RequestHeader("Authorization") String token, HttpServletResponse response) {//如果接受成功则解析token,失败则修改状态码为401try{//模拟token验证Map<String, Object> claims = JwtUtil.parseToken(token);return Result.success("所有的文章数据....");}catch (Exception e){//http响应状态码为401response.setStatus(401);return Result.error("未登录");}}
}
我们在测试接口的时候,要注意先登录,然后复制令牌过来后,设置Heager请求头再加入value的值为令牌,再发送数据请求即可登录使用成功
多功能:
咱们前面是登陆后的一个功能,那么登陆后有多个功能呢?怎么办?
答案是 使用拦截器:
使用拦截器后:
我们使用了拦截器的话,就不用controller类下的拦截了,要注释掉这些拦截功能
编写拦截器接口:
创建一个interceptors拦截器包,下创建一个LoginInterceptor类,编写关于登录的拦截器:
package org.huangyingyuan.interceptors;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.huangyingyuan.pojo.Result;
import org.huangyingyuan.utils.JwtUtil;
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("Autorization");//验证tokentry{//模拟token验证Map<String, Object> claims = JwtUtil.parseToken(token);//放行return true;}catch (Exception e){//http响应状态码为401response.setStatus(401);//不放行return false;}}
}
注册拦截器接口:
在config包下,创建一个WebConfig类【注册拦截器】:
package org.huangyingyuan.config;import org.huangyingyuan.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) {//登录接口(/user/login)和注册类接口(/user/register)不拦截registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login", "/user/register");}
}
结果:
1.没勾选令牌参数配置:
2.勾选了令牌配置:
这样子就实现了“验证令牌headers”的相关操作,实现了多页面跳转的拦截器操作!
干货满满,点个关注,下期更精彩