Jwt请求头校验
This commit is contained in:
parent
16e06994c2
commit
02a294df0e
|
@ -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());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue