gpt4 book ai didi

java - Spring Boot 中永远不会调用 AuthenticationEntryPoint

转载 作者:行者123 更新时间:2023-11-30 05:49:20 25 4
gpt4 key购买 nike

我有一个用于自定义 token 的 Spring Security 实现,我尝试了很多方法来实现身份验证异常的自定义响应,但我找不到解决方案,它从未被调用。

为了安全起见,我有这样的配置:

@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(new AuthenticationExceptionHandler())
// this entry point handles when you request a protected page and you are not yet
// authenticated
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(provider)
.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS)
.authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable()
;
}

这是 TokenAuthenticationProvider:

@Override
protected UserDetails retrieveUser(final String username, final
UsernamePasswordAuthenticationToken authentication) throws
AuthenticationException {
final String token = (String) authentication.getCredentials();
logger.info("Retrieving user details from the token.");
FirebaseToken decodedToken;
UserAuth user = new UserAuth();
try {
decodedToken = FirebaseAuth.getInstance().verifyIdToken(token);
user.setId(decodedToken.getUid());
user.setEmail(decodedToken.getEmail());
user.setName(decodedToken.getName());
user.setClaims(decodedToken.getClaims());
} catch (FirebaseAuthException e) {
e.printStackTrace();
throw new CredentialsExpiredException("Fail getting the idUser
maybe token expired.");
}

return user;
}

当 Firebase token 无效时,我会从 org.springframework.security.authentication 抛出 CredentialsExpiredException,但我仍然收到此答案:

{
"timestamp": "2019-01-16T16:51:54.696+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/employer"
}

这是 AuthenticationEntryPoint:

@Component
public class AuthenticationExceptionHandler implements
AuthenticationEntryPoint, Serializable {

@Override
public void commence(HttpServletRequest request, HttpServletResponse
response, AuthenticationException authException) throws IOException,
ServletException {

response.setStatus(HttpStatus.UNAUTHORIZED.value());

Map<String, Object> error = new HashMap<>();
error.put("domain", "global");
error.put("reason", "required");
error.put("message", "Invalid credentials.");
ArrayList<Map<String, Object>> errorsList = new ArrayList<>();
errorsList.add(error);
Map<String, Object> errors = new HashMap<>();
errors.put("errors", errorsList);
errors.put("code", 401);
errors.put("message", "Invalid credentials.");

Map<String, Object> data = new HashMap<>();
data.put("error", errors);

ObjectMapper mapper = new ObjectMapper();
String responseMsg = mapper.writeValueAsString(data);
response.getWriter().write(responseMsg);
}
}

最佳答案

我解决了这个问题,实现了一个 AuthenticationFailureHandler,该处理程序由在 AbstractAuthenticationProcessingFilter 中实现的 unsuccessfulAuthentication 方法调用...这是配置代码:

@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.exceptionHandling()
// this entry point handles when you request a protected page and you are not yet
// authenticated
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(provider)
.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS)
.authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable()
;
}


@Bean
TokenAuthenticationFilter restAuthenticationFilter() throws Exception {
final TokenAuthenticationFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
filter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
return filter;
}

这是 AuthenticationFailureHandler:

public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {

private ObjectMapper objectMapper = new ObjectMapper();

@Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException {

response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");

Map<String, Object> error = new HashMap<>();
error.put("domain", "global");
error.put("reason", "required");
error.put("message", "Invalid credentials.");
ArrayList<Map<String, Object>> errorsList = new ArrayList<>();
errorsList.add(error);
Map<String, Object> errors = new HashMap<>();
errors.put("errors", errorsList);
errors.put("code", 401);
errors.put("message", "Invalid credentials.");

Map<String, Object> data = new HashMap<>();
data.put(
"error", errors);

response.getOutputStream()
.println(objectMapper.writeValueAsString(data));
}
}

在身份验证流程中,当我抛出 CredentialsExpiredException、BadCredentialsException 或任何身份验证异常时,将从 AbstractAuthenticationProcessingFilter 调用 unsuccessfulAuthentication 方法,并将执行给定的 AuthenticationFailureHandler:

public final class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String BEARER = "Bearer";

public TokenAuthenticationFilter(final RequestMatcher requiresAuth) {
super(requiresAuth);
}

@Override
public Authentication attemptAuthentication(
final HttpServletRequest request,
final HttpServletResponse response) {
final String param = ofNullable(request.getHeader(AUTHORIZATION))
.orElse(request.getParameter("t"));

final String token = ofNullable(param)
.map(value -> removeStart(value, BEARER))
.map(String::trim)
.orElseThrow(() -> new BadCredentialsException("Missing Authentication Token"));

final Authentication auth = new UsernamePasswordAuthenticationToken(null, token);
return getAuthenticationManager().authenticate(auth);
}

@Override
protected void successfulAuthentication(
final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain chain,
final Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException failed)
throws IOException, ServletException {
getFailureHandler().onAuthenticationFailure(request, response, failed);
}
}

关于java - Spring Boot 中永远不会调用 AuthenticationEntryPoint,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54222106/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com