英文:
Spring Boot AccessDecisionVoter custom Unauthorized message
问题
我有一个用于自定义注解的自定义 AccessDecisionVoter,它基于注解中提供的作用域限制对某些方法的访问。这可以正常运行,但是当身份验证缺少范围时,我收到的响应始终相同,我正在寻找一种自定义此响应的方法。提前谢谢。
ScopeVoter
public class ScopeVoter implements AccessDecisionVoter<MethodInvocation> {
@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
// 在这里进行自定义逻辑,决定是否授予或拒绝访问。这里应该自定义消息。
}
}
AuthenticationEntryPoint
@Component
public class AuthenticationEntryPointImp implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未经授权");
}
}
这是生成响应的地方,我正在尝试将自定义消息传递给此 AuthenticationEntryPoint
。
HTTPSecurity 配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
}
authenticationEntryPoint()
是上述描述的类。
PS:我还希望能够从 authFilter()
获取自定义消息传递给 EntryPoint。
编辑:
有人指出这可能是不可能的,但如果不是在 AuthenticationEntryPoint
中,肯定还有其他地方。
而且,我还希望能够从 AuthenticationFilter
在 AuthenticationEntryPoint
中显示自定义消息,当身份验证失败时肯定会调用该消息。
英文:
I have a custom AccessDecisionVoter for a custom Annotation, which restricts the access to certain methods, based on the scopes provided in the Annotation. This works without a problem, but the response I get when the Authentication is missing the scope is always the same and I am looking for a way to customize this. Thank you in advance.
ScopeVoter
public class ScopeVoter implements AccessDecisionVoter<MethodInvocation> {
@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
//custom logic here which decides to grant or deny the access. Here the message should be customized.
}
AuthenticationEntryPoint
@Component
public class AuthenticationEntryPointImp implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
This is where the response is generated and I am trying to get the custom message to this
AuthenticationEntryPoint.
HTTPSecurety Configuration
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
}
authenticationEntryPoint() is the described class above.
PS: I also want to get a custom message from the authFilter() to the EntryPoint.
EDIT:
It was pointed out to me that this might not be possible, but if not in the AuthenticationEntryPoint there must be another place.
And I also want to display a custom message from the AuthenticationFilter in the AuthenticationEntryPoint, which definitely gets called when the auth fails.
答案1
得分: 1
我认为这是不可能的,因为 AuthenticationEntryPoint.commence() 和 AccessDecisionVoter.voter() 是互斥的,当认证失败时,不会调用投票者(voter),当认证成功时,不会调用启动(commence)()。
英文:
I think it is impossible to do this, because AuthenticationEntryPoint.commence() and AccessDecisionVoter.voter() is mutual exclusion, when the authentication is failure, the voter will not be called, when the authentication is success, the commence will not be called()
答案2
得分: 1
关于你提到的自定义错误响应部分:我已经配置了CustomAuthenticationEntryPoint
,使其调用了我用@ControllerAdvice
定义的通用异常处理程序。
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException {
resolver.resolveException(request, response, null, ex);
}
}
源代码在这里可用。
英文:
For the customized error response part of your question: I have configured CustomAuthenticationEntryPoint
so that it invokes my general exception handler defined with @ControllerAdvice.
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException {
resolver.resolveException(request, response, null, ex);
}
}
Source code is available here.
答案3
得分: 1
如果使用者成功通过身份验证,但选民被拒绝,您可以配置您的 AccessDeniedHandler
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.getWriter().println(accessDeniedException.getMessage());
}
}).authenticationEntryPoint(authenticationEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
}
然后在 ScopeVoter 中,您可以自行抛出 AccessDeniedException
public class ScopeVoter implements AccessDecisionVoter<MethodInvocation> {
@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
// 如果逻辑不满足,直接抛出异常
throw new AccessDeniedException("您的自定义消息在这里");
}
}
英文:
if use is authenticated successfully, and then the voter is denied, you can configure your AccessDeniedHandler
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.getWriter().println(accessDeniedException.getMessage());
}
}).authenticationEntryPoint(authenticationEntryPoint()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
}
then in ScopeVoter, you can throw AccessDeniedException by yourself
public class ScopeVoter implements AccessDecisionVoter<MethodInvocation> {
@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
//if the logic is not met, throw it directly
throw new AccessDeniedException("your customize message is here");
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论