Spring Boot AccessDecisionVoter自定义未授权消息

时间:2020-08-19 16:56:01

标签: java spring spring-boot spring-security

我有一个用于自定义注释的自定义 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的自定义消息,当身份验证失败时肯定会调用该消息。

3 个答案:

答案 0 :(得分:1)

enter image description here

我认为这是不可能的,因为 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");
}