构造登录函数
在userController添加登录的构造函数
@PostMapping("login")
public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$")String password){
//根据用户名查询用户
User loginUser =userService.findByUserName(username);
if(loginUser==null){
return Result.error("用户名错误");
}
//判断密码是否正确 密码是密文
if(MdUtil.getMDString(password).equals(loginUser.getPassword())){
return Result.success("登录成功");
}
return Result.error("密码错误");
}
在postman上进行登录
登录认证
设计登录认证,使用户必须先登录才能访问其他接口
我们新建一个ArticleController类进行测试
package com.example.Controller;
import com.example.Pojo.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("article")
public class ArticleController {
@GetMapping("list")
public Result<String> list(){
return Result.success("测式登录认证");
}
}
试试在不等录的情况下能否访问
发现能访问,这是不可以的
所以,我们必须借助令牌接口,进行身份识别
令牌:一段数据,承载业务数据,减少后续请求查询数据库的次数,同时要防止篡改,保证信息的合法和有效性
JWT令牌
jwt定义了一种简洁,自身包含的格式,用于通信双方以json数据格式安全的传输信息;
1生成令牌
导入依赖
<!--导入JWT依赖-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
设置工具类JWTUtils
package com.example.Utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JWTUtil {
private static final String KEY="horobi";
public static String getToken(Map<String,Object> claim) {
//生成jwt的代码
String token= JWT.create().
withClaim("user",claim)//添加载荷
.withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))//添加过期时间,当前时间后的1000*60*60*12毫秒
.sign(Algorithm.HMAC256(KEY));//配置算法并指定密钥
//System.out.println("这是token:\n"+token);
return token;
}
public static Map<String, Object> parseToken(String token){
//验证JWT
//生成的token
JWTVerifier horobi = JWT.require(Algorithm.HMAC256(KEY)).build();
DecodedJWT verify = horobi.verify(token);//验证token,生成一个解析器
Claim user = verify.getClaim("user");
Map<String, Object> claim = user.asMap();
// JWT.require(Algorithm.HMAC256(KEY))
// .build()
// .verify(token)
// .getClaim("claims")
// .asMap();
//过期也会验证失败
return claim;
}
}
2重写登录方法
@PostMapping("login")
public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$")String password){
//根据用户名查询用户
User loginUser =userService.findByUserName(username);
if(loginUser==null){
return Result.error("用户名错误");
}
//判断密码是否正确 密码是密文
if(MdUtil.getMDString(password).equals(loginUser.getPassword())){
//登录成功
Map<String,Object> claim=new HashMap<>();
claim.put("id",loginUser.getId());
claim.put("username",loginUser.getUsername());
String token = JWTUtil.getToken(claim);
return Result.success(token);
}
return Result.error("密码错误");
}
用户在登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,浏览器都需要请求header中携带到服务器端,请求头的名称为Authorization,值为登录时下发的JWT令牌,如果检查到用户为登录,则http响应为401(未授权)
3在ArticleController写验证token
@GetMapping("list")
public Result<String> list(@RequestHeader(name="Authorization") String token, HttpServletResponse response){
//验证token
try{
Map<String, Object> claim = JWTUtil.parseToken(token);
}catch (Exception e){
//http响应码为401
response.setStatus(401);
return Result.success("未登录");
}
return Result.success("测式登录认证");
}
4验证
登录
再去
拦截器
设置一个拦截器,这样就不用在每个请求里面设置方法
新建Interceptors包,新建LoginInterceptor
package com.example.Interceptors;
import com.auth0.jwt.interfaces.Claim;
import com.example.Pojo.Result;
import com.example.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//把拦截器放入IOC容器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//令牌验证
String token = request.getHeader("Authorization");
//验证token
try{
Map<String, Object> claim = JWTUtil.parseToken(token);
}catch (Exception e){
//http响应码为401
response.setStatus(401);
System.out.println("可能没有登录");
return false;//不放行
}
return true;//放行
}
}
新建Config包,新建WebConfig为配置类
package com.example.Config;
import com.example.Interceptors.LoginInterceptor;
import jakarta.annotation.Resource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class WebConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {//注册拦截器
registry.addInterceptor(loginInterceptor)
.excludePathPatterns("/user/login","/user/register")//登录接口和注册接口不拦截
}
}
再修改ArticleController进行测试