1.登录
package com.itheima.springbootconfigfile.controller;import com.itheima.springbootconfigfile.pojo.Result;
import com.itheima.springbootconfigfile.pojo.User;
import com.itheima.springbootconfigfile.service.UserService;import com.itheima.springbootconfigfile.utils.MailUtil1;
import jakarta.validation.constraints.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/user")
@Validated
public class UserController {@Autowiredprivate UserService userService;// public User findById(Integer id){
// return userService.findById(id);
// }//注册@GetMapping("/register")public Result register(@Pattern(regexp="^\\S{5,16}$")String username, @Pattern(regexp = "^\\S{5,16}$") String password){//参数校验
//
// if(username!=null&&username.length()>=5&&username.length()<=16&&
// password!=null&&password.length()>=5&&password.length()<=16
// ){//用户名是否存在User user=userService.findByUserName(username);if(user==null){//不存在则注册userService.register(username,password);return Result.success();//输出操作成功} else{//若已存在return Result.error("用户名已占用");}//参数校验
// }else{
// return Result.error("参数不合法");
//
// }}@GetMapping("/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(MailUtil1.getMD5String(password).equals(loginuser.getPassword())){return Result.success("jwt token令牌");}return Result.error("密码错误");}
}
未登录(即无token,无header),却能访问:
->2.最常用的令牌Token(Token:要求防篡改):
JWT:用于WEB,基于Json的令牌
格式:
header头(alg:签名算法,type:令牌类型JWT) . payload有效载荷(id,username)(不能有password等私密数据,因为这里边用的加密方式是公开的)= . signature签名(防止Token被篡改,确保安全,将header,paload加入指定密钥,通过指定签名算法技算得到)
代码展示:
1.JWT生成
<!--java-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>-->
package com.itheima;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","张三");//生成jwtString token=JWT.create().withClaim("user",claims).withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12)).sign(Algorithm.HMAC256("itheima"));//添加载荷,过期时间:12h,指定算法和密钥System.out.println(token);}
}
2.JWT验证
package com.itheima;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 org.junit.jupiter.api.Test;import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class JwtTest {//JWT生成@Testpublic void testGen(){Map<String,Object> claims=new HashMap<>();claims.put("id",1);claims.put("username","张三");//生成jwtString token=JWT.create().withClaim("user",claims).withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*24)).sign(Algorithm.HMAC256("itheima"));//添加载荷,过期时间:12h,指定算法和密钥System.out.println(token);}//JWT验证@Testpublic void testParse(){//将user传过来的token,定义为tokenString token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuW8oOS4iSJ9LCJleHAiOjE3MzkxODY0NzR9" +".xSK7L5wUpvbYcxGsloRuZA1arBez87cpv2K0s_odk00";//生成验证器JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256("itheima")).build();//验证token,生成解析后的JWT对象DecodedJWT decodedJWT=jwtVerifier.verify(token);Map<String, Claim> claimMap=decodedJWT.getClaims();System.out.println(claimMap.get("user"));//如果能输出user的id,username,说明根据该token 解析成功}}
报错:
修改:
重新生成token,并修改验证方法中的token,再次运行,成功!
举例:若修改载荷,则token失效,时间过期,密钥错误都会失效
3.登录认证(登录时生成token->验证token,错误:401)
1.普通:
@GetMapping("/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(MailUtil1.getMD5String(password).equals(loginuser.getPassword())){Map<String,Object> claims=new HashMap<>();claims.put("id",loginuser.getId());claims.put("username",loginuser.getUsername());String token= JwtUtil.genToken(claims);//以上是为了把JwtTest没有的补充完,然后调用genToken()return Result.success(token);}return Result.error("密码错误");}
?????????????????猜测:到这一步仅仅是生成token.还没写验证token
2.拦截器:
1.生成拦截器
1.目的:会有很多Controller,都要进行某一步时,选择拦截器:
HandlerInterceptor
接口用于拦截处理器(Controller方法)的执行生成token已经有了(在每个Controller中),现在进行token验证
2.运行顺序:搜索/artical/list时,未登录情况下会调用拦截器:先经过WebConfig,再调用拦截器LoginInterceptor,若失败则返回401,若成功则返回ArticalController中的
return Result.success("所有的文章数据");
ArticalController:
package com.itheima.springbootconfigfile.controller;import com.itheima.springbootconfigfile.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("/artical")
public class ArticalController {@GetMapping("/list")public Result<String> list(){return Result.success("所有的文章数据");}
}
package com.itheima.springbootconfigfile.interceptors;import com.itheima.springbootconfigfile.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 {//token验证@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//得到tokenString token=request.getHeader("Authorization");//验证tokentry {Map<String,Object> claims= JwtUtil.parseToken(token);return true;}catch (Exception e){response.setStatus(401);return false;}}
}
request:请求, 从请求头中获取Authorization来获取token
response:响应,设置HTTP响应状态码是401
2.注册该拦截器:
package com.itheima.springbootconfigfile.config;import com.itheima.springbootconfigfile.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/register","/user/login");}
}
运行:
有Authorization(即有token)->success:
无->error