首先,我正在尝试学习 Spring 安全性,可能我的问题很幼稚。我正在尝试将 JWT 令牌从反应 UI 发送到后端 Spring Boot 安全性,但它不起作用。但是,我可以在邮递员中进行相同的测试,并且效果很好。我有以下文件 -
AppController.java
@RestController
@CrossOrigin("*")
@RequestMapping("/files")
public class AppController{
@PostMapping("/import")
public boolean runImport(@RequestBody String file, @RequestParam(value = "year") String year) throws Exception {
//some processing
}
JWTAuthorizationFilter.java
public class JWTAuthorizationFilter extends OncePerRequestFilter {
private final String HEADER = "Authorization";
private final String PREFIX = "Bearer ";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
try {
if (checkJWTToken(request, response)) {
DecodedJWT decoded = validateToken(request);
setUpSpringAuthentication(decoded, decoded.getClaims().get("Username").asString());
} else {
SecurityContextHolder.clearContext();
}
chain.doFilter(request, response);
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
return;
}
}
private DecodedJWT validateToken(HttpServletRequest request) {
String jwtToken = request.getHeader(HEADER).replace(PREFIX, "");
DecodedJWT decoded = JWT.decode(jwtToken);
return decoded;
}
private void setUpSpringAuthentication(DecodedJWT claims, String Subject) {
List<HashMap> Auth = new ArrayList<HashMap>();
Auth = claims.getClaim("UserFunctions").asList(HashMap.class);
List<String> Roles = new ArrayList<String>();
for (HashMap userFunction : Auth) {
Roles.add(userFunction.get("name").toString());
}
String allowedRoles[] = {"Admin","Moderator" };
Collection<String> intersection = CollectionUtils.intersection(Roles, Arrays.asList(allowedRoles));
if (intersection.size() > 0) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(Subject, null,
Roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
SecurityContextHolder.getContext().setAuthentication(auth);
} else {
throw new UnsupportedJwtException("Role Not supported");
}
}
private boolean checkJWTToken(HttpServletRequest request, HttpServletResponse res) {
String authenticationHeader = request.getHeader(HEADER);
if (authenticationHeader == null || !authenticationHeader.startsWith(PREFIX))
return false;
return true;
}
}
WebSecurityConfig.java
@EnableWebSecurity
@Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().addFilterAfter(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/files/import")
.hasAnyAuthority("Admin")
.anyRequest().authenticated();
}
}
身份验证入口点
JWTAuthenticationEntryPoint
@Component
public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(JWTAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
org.springframework.security.core.AuthenticationException authException)
throws IOException, ServletException {
logger.error("Responding with unauthorized error. Message - {}", authException.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}
当我尝试与前端通信时,我在控制台上收到以下错误,但在前端没有消息。日志
2020-10-28 14:07:06 - Did not match
2020-10-28 14:07:06 - Request not saved as configured RequestMatcher did not match
2020-10-28 14:07:06 - Calling Authentication entry point.
2020-10-28 14:07:06 - Using @ExceptionHandler org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#mediaTypeNotAcceptable(HttpServletRequest)
2020-10-28 14:07:06 - Pre-authenticated entry point called. Rejecting access
2020-10-28 14:07:06 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@7e82ef7
2020-10-28 14:07:06 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-10-28 14:07:06 - SecurityContextHolder now cleared, as request processing completed
2020-10-28 14:07:06 - Using 'text/event-stream', given [text/event-stream] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2020-10-28 14:07:06 - Nothing to write: null body
2020-10-28 14:07:06 - Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
2020-10-28 14:07:06 - Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2020-10-28 14:07:06 - /error at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-10-28 14:07:06 - Exiting from "ERROR" dispatch, status 403
2020-10-28 14:07:06 - /error at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-10-28 14:07:06 - No HttpSession currently exists
2020-10-28 14:07:06 - No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-10-28 14:07:06 - Chain processed normally
2020-10-28 14:07:06 - /error at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-10-28 14:07:06 - /error at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2020-10-28 14:07:06 - Trying to match using Ant [pattern='/logout', GET]
2020-10-28 14:07:06 - Checking match of request : '/error'; against '/logout'
2020-10-28 14:07:06 - Trying to match using Ant [pattern='/logout', POST]
2020-10-28 14:07:06 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-10-28 14:07:06 - SecurityContextHolder now cleared, as request processing completed
2020-10-28 14:07:06 - Request 'GET /error' doesn't match 'POST /logout'
2020-10-28 14:07:06 - Trying to match using Ant [pattern='/logout', PUT]
2020-10-28 14:07:06 - Request 'GET /error' doesn't match 'PUT /logout'
2020-10-28 14:07:06 - Trying to match using Ant [pattern='/logout', DELETE]
2020-10-28 14:07:06 - Request 'GET /error' doesn't match 'DELETE /logout'
2020-10-28 14:07:06 - No matches found
2020-10-28 14:07:06 - /error at position 5 of 11 in additional filter chain; firing Filter: 'JWTAuthorizationFilter'
2020-10-28 14:07:06 - /error at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-10-28 14:07:06 - saved request doesn't match
2020-10-28 14:07:06 - /error at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-10-28 14:07:06 - /error at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-10-28 14:07:06 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@35fe44ce: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2020-10-28 14:07:06 - /error at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-10-28 14:07:06 - /error at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-10-28 14:07:06 - /error at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-10-28 14:07:06 - /error reached end of additional filter chain; proceeding with original chain
2020-10-28 14:07:06 - "ERROR" dispatch for GET "/error", parameters={}
2020-10-28 14:07:06 - Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2020-10-28 14:07:06 - Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2020-10-28 14:07:06 - Using @ExceptionHandler org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#mediaTypeNotAcceptable(HttpServletRequest)
2020-10-28 14:07:06 - Using 'text/event-stream', given [text/event-stream] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2020-10-28 14:07:06 - Nothing to write: null body
2020-10-28 14:07:06 - Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
2020-10-28 14:07:06 - Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2020-10-28 14:07:06 - Exiting from "ERROR" dispatch, status 403
2020-10-28 14:07:06 - Chain processed normally
2020-10-28 14:07:06 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-10-28 14:07:06 - SecurityContextHolder now cleared, as request processing completed
2020-10-28 14:07:06 - [Consumer clientId=consumer-berichtskreisverwaltung-service-1, groupId=berichtskreisverwaltung-service] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
2020-10-28 14:07:06 - [Consumer clientId=consumer-berichtskreisverwaltung-service-1, groupId=berichtskreisverwaltung-service] Bootstrap broker localhost:9092 (id: -1 rack: null) disconnected
2020-10-28 14:07:08 - /sse/register at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-10-28 14:07:08 - /sse/register at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-10-28 14:07:08 - No HttpSession currently exists
2020-10-28 14:07:08 - No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-10-28 14:07:08 - /sse/register at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-10-28 14:07:08 - /sse/register at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2020-10-28 14:07:08 - Trying to match using Ant [pattern='/logout', GET]
2020-10-28 14:07:08 - Checking match of request : '/sse/register'; against '/logout'
2020-10-28 14:07:08 - Trying to match using Ant [pattern='/logout', POST]
2020-10-28 14:07:08 - Request 'GET /sse/register' doesn't match 'POST /logout'
2020-10-28 14:07:08 - Trying to match using Ant [pattern='/logout', PUT]
2020-10-28 14:07:08 - Request 'GET /sse/register' doesn't match 'PUT /logout'
2020-10-28 14:07:08 - Trying to match using Ant [pattern='/logout', DELETE]
2020-10-28 14:07:08 - Request 'GET /sse/register' doesn't match 'DELETE /logout'
2020-10-28 14:07:08 - No matches found
2020-10-28 14:07:08 - /sse/register at position 5 of 11 in additional filter chain; firing Filter: 'JWTAuthorizationFilter'
2020-10-28 14:07:08 - /sse/register at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-10-28 14:07:08 - saved request doesn't match
2020-10-28 14:07:08 - /sse/register at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-10-28 14:07:08 - /sse/register at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-10-28 14:07:08 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@35fe44ce: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2020-10-28 14:07:08 - /sse/register at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-10-28 14:07:08 - /sse/register at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-10-28 14:07:08 - /sse/register at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-10-28 14:07:08 - Request 'GET /sse/register' doesn't match 'POST /files/import'
2020-10-28 14:07:08 - Secure object: FilterInvocation: URL: /sse/register; Attributes: [authenticated]
2020-10-28 14:07:08 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@35fe44ce: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2020-10-28 14:07:08 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@3d047e19, returned: -1
2020-10-28 14:07:08 - Access is denied (user is anonymous); redirecting to authentication entry point
用户被自动指定为匿名用户。我无法调试它,因为控件永远不会出现在 runImport() 方法中。有人可以指出我的代码中缺少什么吗?