![](/img/trans.png)
[英]Spring security return 401/403 instead of redirecting the user to the login page
[英]Spring Security anonymous 401 instead of 403
我在 Spring Security 中的默认行为与 Java Config 提供的授权请求有关。
http
....
.authorizeRequests()
.antMatchers("/api/test/secured/*").authenticated()
当我在没有登录的情况下(使用匿名用户)调用例如/api/test/secured/user
,它返回 403 Forbidden。 当匿名用户想要通过authenticated()
或@PreAuthorize
资源获得保护时,是否有一种简单的方法可以将状态更改为 401 Unauthorized?
从 Spring Boot 2 开始,Http401AuthenticationEntryPoint 类已被删除(参见Spring Boot 问题 10725 )。
而不是 Http401AuthenticationEntryPoint 使用 HttpStatusEntryPoint 和 HttpStatus.UNAUTHORIZED:
http.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
使用 spring security 4.x 已经有一个类
org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
Spring Boot 还包括一个
org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint
并且他们要求开发人员使用符合规范的两个好处,因为401 响应要求必须设置标头 WWW-Authenticate ,例如 401 响应可以是:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"
因此,在您的安全配置中,您定义并自动装配了一个类的 bean
因此,例如使用 Spring Boot 应用程序:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Bean
public Http401AuthenticationEntryPoint securityException401EntryPoint(){
return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
}
...
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").anonymous()
.antMatchers("/").anonymous()
.antMatchers("/api/**").authenticated()
.and()
.csrf()
.disable()
.headers()
.frameOptions().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.logout()
.permitAll()
.exceptionHandling().authenticationEntryPoint(securityException401EntryPoint());
}
相关行是:
.exceptionHandling().authenticationEntryPoint(securityException401EntryPoint());
我在这里有解决方案:
http
.authenticationEntryPoint(authenticationEntryPoint)
AuthenticationEntryPoint 源代码:
@Component
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {
private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);
/**
* Always returns a 401 error code to the client.
*/
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException,
ServletException {
log.debug("Pre-authenticated entry point called. Rejecting access");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
}
}
您需要扩展AuthenticationEntryPoint
以根据异常进行自定义。
@ControllerAdvice
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
// 401
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed");
}
@ExceptionHandler (value = {AccessDeniedException.class})
public void commence(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
// 401
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Failed : " + accessDeniedException.getMessage());
}
}
在您的 SecurityConfig 中指定上述自定义 AuthenticationEntryPoint ,如下所示:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity (prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new MyAuthenticationEntryPoint());
}
}
Spring Boot 2 中使用 lambda 表达式的一种简单方法:
@Override
public void configure(HttpSecurity http) throws Exception {
http.
...
.exceptionHandling()
.authenticationEntryPoint((request, response, e) -> {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");
response.getWriter().write("{ \"error\": \"You are not authenticated.\" }");
})
...
}
谁对工作机制感兴趣。
如果你没有设置http.exceptionHandling().authenticationEntryPoint()
spring 将使用defaultAuthenticationEntryPoint()
并且方法ExceptionHandlingConfigurer.createDefaultEntryPoint()
将返回new Http403ForbiddenEntryPoint()
所以,只需创建Http401UnauthorizedEntryPoint()
。 上面回答了怎么做,没有重复。
PS 这是 Spring Security 5.2.5.RELEASE 的实际情况
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.