Spring Security如何处理UsernameNotFoundException [英] How to handle UsernameNotFoundException spring security
问题描述
如何处理 UsernameNotFoundException
吗?
在春季安全性中,找不到用户名 UserDetailsService
实现会引发 UsernameNotFoundException
。像这样的例子:
In spring security when username not found the UserDetailsService
implementation throws a UsernameNotFoundException
. For example like this:
@Override
@Transactional
public UserDetails loadUserByUsername(java.lang.String username) throws UsernameNotFoundException {
logger.info("Load user by username: {}", username);
User user = userRepository.findUserByUsername(username).orElseThrow(
() -> new UsernameNotFoundException("User Not Found with -> username or email: " + username));
return UserPrinciple.build(user);
}
我想构建一个自定义的找不到用户REST响应。
如何捕获/处理此异常?我已经在WebSecurityConfigurerAdapter实现的处理程序中实现了处理程序方法:
I would like to build a custom "User not found REST response". How should I catch/handle this exception? I have implemented a handler method in the WebSecurityConfigurerAdapter implementation the handler:
private static void handleException(HttpServletRequest req, HttpServletResponse rsp, AuthenticationException e)
throws IOException {
PrintWriter writer = rsp.getWriter();
writer.println(new ObjectMapper().writeValueAsString(new AuthResponse("", null, null, null, null,
"Authentication failed.", false)));
rsp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
但是此方法应等待 AuthenticationException
异常,在运行时,异常类型为 java.lang.NullPointerException
,因此我无法投射或检索初始的 UsernameNotFoundException
。
But this method should wait for an AuthenticationException
exception which, and during runtime the type of the exception is java.lang.NullPointerException
so I'm not able to cast or retrieve the the initial UsernameNotFoundException
.
任何建议将不胜感激。
很多方面的问候:)。
Any advice would be appreciated. Many many regards :).
推荐答案
安全层先于控制器和 @ControllerAdvice
。
因此, @ControllerAdvice
是不可选项,因为 UsernameNotFoundException
是 AuthenticationException
,从而使 @ControllerAdvice
中的异常处理程序无法访问。
Security layer comes before anything in the controllers and @ControllerAdvice
.
Hence @ControllerAdvice
isn't an option since UsernameNotFoundException
which is a subclass of AuthenticationException
is thrown during authenticaton, making your exception handlers in @ControllerAdvice
unreachable.
如果以下情况,您只能使用 @ControllerAdvice
和 ResponseEntityExceptionHandler
您在控制器或控制器引用的任何其他bean中抛出 UsernameNotFoundException
。
You can only use @ControllerAdvice
and ResponseEntityExceptionHandler
if you are throwing UsernameNotFoundException
inside controller or any others beans referenced from the controllers.
这是我的建议-您实现 AuthenticationFailureHandler
并将其与用于安全配置的 AuthenticationFilter
一起使用。
春季启动安全性带有约4个处理程序接口,用于处理与安全性相关的问题
Here is my suggestion - that you implement AuthenticationFailureHandler
and use it with AuthenticationFilter
that you are using for your security configuration.
Spring boot security comes with about 4 handler interfaces for security related issues
-
AccessDeniedHandler
-处理诸如用户不具有所需角色时的问题。 -
AuthenticationEntryPoint
-处理诸如时的问题用户尝试在没有适当身份验证元素的情况下访问资源。
AccessDeniedHandler
- this handles issues like when a user not having required roles.AuthenticationEntryPoint
- this handles issues like when a user tries to access a resource without appropriate authentication elements.
AuthenticationFailureHandler
-处理诸如以下情况的问题找不到用户(即 UsernameNotFoundException
)或身份验证提供程序内引发的其他异常。实际上,这可以处理 AccessDeniedException
和 AuthenticationEntryPoint
未处理的其他身份验证异常。
AuthenticationFailureHandler
- this handles issues like when a user is not found(i.e. UsernameNotFoundException
) or other exceptions thrown inside authentication provider. In fact, this handles other authentication exceptions that are not handled by AccessDeniedException
and AuthenticationEntryPoint
.
AuthenticationSuccessHandler
-这有助于在用户成功通过身份验证后执行重定向之类的工作。
AuthenticationSuccessHandler
- this helps to do stuff like redirection after a user is successfully authenticated.
有关所有4个接口的实现,请参见以下示例代码段。请根据您的喜好自定义它们。
See the following example snippets for the implementation of all the 4 interfaces. Please customize these to your taste.
-
AccessDeniedHandler
实现
AccessDeniedHandler
implementation
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
Map<String,Object> response = new HashMap<>();
response.put("status","34");
response.put("message","unauthorized api access");
//httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
OutputStream out = httpServletResponse.getOutputStream();
ObjectMapper mapper = new ObjectMapper();
mapper.writerWithDefaultPrettyPrinter().writeValue(out,response);
//mapper.writeValue(out, response);
out.flush();
}
}
-
AuthenticationEntryPoint
实现
AuthenticationEntryPoint
Implementation
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
Map<String,Object> response = new HashMap<>();
response.put("status","34");
response.put("message","unauthorized access");
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
OutputStream out = httpServletResponse.getOutputStream();
ObjectMapper mapper = new ObjectMapper();
mapper.writerWithDefaultPrettyPrinter().writeValue(out, response);
out.flush();
}
}
-
AuthenticationFailureHandler
实现
AuthenticationFailureHandler
implementation
package com.ibiller.webservices.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
@Component
public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler
{
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse httpServletResponse,
AuthenticationException ex) throws IOException, ServletException
{
Map<String,Object> response = new HashMap<>();
response.put("status","34");
response.put("message","unauthorized access");
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
OutputStream out = httpServletResponse.getOutputStream();
ObjectMapper mapper = new ObjectMapper();
mapper.writerWithDefaultPrettyPrinter().writeValue(out, response);
out.flush();
}
}
-
AuthenticationSuccessHandler
实现
AuthenticationSuccessHandler
implementation
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class RestSuccessHandler implements AuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
Set<String> roles =
AuthorityUtils.authorityListToSet(authentication.getAuthorities());
if (roles.contains("ROLE_ADMIN")) {
//do something
}
}
}
这是扩展 WebSecurityConfigurerAdapter
的安全性配置,将所有内容连接在一起。
This is the Security configuration that extends WebSecurityConfigurerAdapter
that connects everything together.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/v1/**"),new AntPathRequestMatcher("/admin/**")
);
AuthenticationProvider provider;
public SecurityConfiguration(final AuthenticationProvider authenticationProvider) {
super();
this.provider=authenticationProvider;
}
@Override
protected void configure(final AuthenticationManagerBuilder auth) {
auth.authenticationProvider(provider);
}
@Override
public void configure(final WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/info/**");//url that will be ignored
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
.authenticationEntryPoint(authenticationEntryPoint())
.and()
.authenticationProvider(provider)
.addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/v1/**").hasRole("API")
.antMatchers("/admin/**").hasAnyRole("SUPER_ADMIN","ADMIN")
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
}
@Bean
AuthenticationFilter authenticationFilter() throws Exception {
final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
filter.setAuthenticationFailureHandler(authenticationFailureHandler());
return filter;
}
@Bean
RestAccessDeniedHandler accessDeniedHandler() {
return new RestAccessDeniedHandler();
}
@Bean
RestAuthenticationEntryPoint authenticationEntryPoint() {
return new RestAuthenticationEntryPoint();
}
@Bean
RestAuthenticationFailureHandler authenticationFailureHandler(){
return new RestAuthenticationFailureHandler();
}
@Bean
RestSuccessHandler successHandler(){
return new RestSuccessHandler();
}
}
这篇关于Spring Security如何处理UsernameNotFoundException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!