我有一个用于自定义注释的自定义 AccessDecisionVoter ,它基于注释中提供的范围,限制了对某些方法的访问。这可以正常工作,但是当缺少身份验证时,我得到的响应始终是相同的,我正在寻找一种自定义方法。预先谢谢你。
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");
}
}
这是生成响应的地方,我正在尝试为此发送自定义消息 AuthenticationEntryPoint。
HTTPSecurety配置
@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中,则必须有另一个位置。 而且我还想在AuthenticationEntryPoint中显示来自AuthenticationFilter的自定义消息,当身份验证失败时肯定会调用该消息。
答案 0 :(得分:1)
我认为这是不可能的,因为 AuthenticationEntryPoint.commence()和 AccessDecisionVoter.voter()是互斥的,当身份验证失败时,投票者将不会被调用,当身份验证成功时,开始将不会被调用()
答案 1 :(得分: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);
}
}
源代码可用here。
答案 2 :(得分: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) {
//if the logic is not met, throw it directly
throw new AccessDeniedException("your customize message is here");
}