Jwt请求头校验

This commit is contained in:
Amadeus 2024-04-21 17:32:27 +08:00
parent 16e06994c2
commit 02a294df0e
5 changed files with 148 additions and 3 deletions

View File

@ -2,6 +2,7 @@ package com.example.config;
import com.example.entity.RestBean;
import com.example.entity.vo.response.AuthorizeV0;
import com.example.filter.JwtAuthorizeFilter;
import com.example.utils.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
@ -9,13 +10,17 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException;
@ -23,6 +28,9 @@ import java.io.IOException;
public class SecurityConfiguration {
@Resource
JwtUtils utils;
@Resource
JwtAuthorizeFilter jwtAuthorizeFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
@ -41,33 +49,57 @@ public class SecurityConfiguration {
.logoutSuccessHandler(this::onLogoutSuccess)
)
.exceptionHandling(conf -> conf
.authenticationEntryPoint(this::onUnauthorized)
//用户登录了但没有权限访问一些资源
.accessDeniedHandler(this::onAccessDeny)
)
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(conf -> conf
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthorizeFilter , UsernamePasswordAuthenticationFilter.class)
.build();
}
//403被禁止的处理
public void onAccessDeny(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException, ServletException {
response.setContentType("application/jason;charset=utf-8");
response.getWriter().write(RestBean.forbidden(exception.getMessage()).asJsonString());
}
private void onUnauthorized(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
response.setContentType("application/jason;charset=utf-8");
response.getWriter().write(RestBean.unauthorized(e.getMessage()).asJsonString());}
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
User user = (User) authentication.getPrincipal();
String token = utils.createJwt(user , 1 , "小明"); //随便起一个id和用户名 作为令牌的
String token = utils.createJwt(user , 1 , "小明");
AuthorizeV0 v0 = new AuthorizeV0();
v0.setExpire(utils.expireTime());
v0.setRole("");
v0.setToken(token);
v0.setUsername("小明");
response.getWriter().write(RestBean.success(v0).asJsonString()); //将实体对象v0返回
response.getWriter().write(RestBean.success(v0).asJsonString());
}
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(RestBean.failure(401 , exception.getMessage()).asJsonString());
response.getWriter().write(RestBean.unauthorized( exception.getMessage()).asJsonString());
}

View File

@ -0,0 +1,15 @@
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/test")
public class TestController {
@GetMapping("/hello")
public String test(){
return "Hello world";
}
}

View File

@ -10,12 +10,21 @@ public record RestBean<T>(int code , T data , String message) {
}
public static <T> RestBean<T> success(){
return success(null);
}
public static <T> RestBean unauthorized(String message){
return failure(401 , message);
}
//403
public static <T> RestBean forbidden(String message){
return failure(403 , message);
}
public static <T> RestBean<T> failure(int code , String message){
return new RestBean<>(code , null , message);
}
public String asJsonString(){
return JSONObject.toJSONString(this, JSONWriter.Feature.WriteNulls);
}

View File

@ -0,0 +1,42 @@
package com.example.filter;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.utils.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class JwtAuthorizeFilter extends OncePerRequestFilter {
@Resource
JwtUtils utils;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
//从请求头中拿到token
String authorization = request.getHeader("Authorization");
DecodedJWT jwt = utils.resolverJwt(authorization);
if(jwt != null){ //jwt不为空则进行解析 为空则进入下一个过滤器链
UserDetails user = utils.toUser(jwt);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(user ,null,user.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
request.setAttribute("id",utils.toId(jwt));
}
filterChain.doFilter(request , response);
}
}

View File

@ -1,15 +1,21 @@
package com.example.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
@Component
public class JwtUtils {
@ -19,6 +25,47 @@ public class JwtUtils {
@Value("${spring.security.jwt.expire}")
int expire;
//解析jwt
public DecodedJWT resolverJwt(String headerToken){
String token =this.convertToken(headerToken);
if (token == null ) return null;
Algorithm algorithm = Algorithm.HMAC256(key);
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
//验证jwt是否被用户篡改过,是的话抛出异常
try {
DecodedJWT verify = jwtVerifier.verify(token);
Date expiresAt = verify.getExpiresAt(); //判断token是否过期
return new Date().after(expiresAt) ? null : verify;
} catch (JWTVerificationException e) {
return null;
}
}
private String convertToken(String headerToken){
if(headerToken == null || !headerToken.startsWith("Bearer")) //判断token是否合法
return null;
return headerToken.substring(7); //返回切割掉Bearer之后的token
}
//解析Jwt中用户数据的方法
public UserDetails toUser(DecodedJWT jwt){
Map<String, Claim> claims = jwt.getClaims();
return User
.withUsername(claims.get("name").asString()) //存疑关于是name还是username
.password("******")
.authorities(claims.get("authorities").asArray(String.class))
.build();
}
//将jwt中的id转换为int数据
public Integer toId(DecodedJWT jwt){
Map<String, Claim> claims = jwt.getClaims();
return claims.get("id").asInt();
}
public String createJwt(UserDetails details , int id , String username){
Algorithm algorithm = Algorithm.HMAC256(key);
Date expire = this.expireTime();