Java 检查经过身份验证的用户是否可以访问URL

Java 检查经过身份验证的用户是否可以访问URL,java,spring-boot,spring-security,Java,Spring Boot,Spring Security,我已经使用spring-security-4.2.2设置了spring-boot-1.5.3应用程序,并根据权限配置了受限路径。这些限制与此类似: @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override pr

我已经使用
spring-security-4.2.2
设置了
spring-boot-1.5.3
应用程序,并根据权限配置了受限路径。这些限制与此类似:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/accounts/**", "/roles/**")
                    .hasAuthority(ADMINISTRATOR)
                    .and()
                .antMatchers("/**")
                    .hasAuthority(USER)
                    .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll()
                .and()
            .csrf()
                .disable();
    }
}
简而言之,我希望拥有权限的用户能够访问我的整个web应用程序,除了
/accounts/**
/roles/**
路径之外。此配置工作正常,如果我尝试在没有适当权限的情况下访问这些页面,则会出现预期错误(403)

对于具有
USER
权限的用户,我想隐藏一些URL,这样他们就不会发出这些请求并得到
403
错误如何检查是否允许用户访问URL

到目前为止,我已经尝试注入
webinvocationprivilegeeevaluator
并调用它的
是允许的
方法,尽管这似乎不起作用。例如:

// Helper class that returns authentication instance.
Authentication auth = AuthUtils.getAuthentication();

// Don't have permission to access /users, expect to get false result.
boolean res = webInvocationPrivilegeEvaluator.isAllowed("/users", auth );

assert res == false; // fails

而是使用方法检查用户是否具有权限

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

而是使用方法检查用户是否具有权限

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

通过访问SpringSecurity的内部过滤器,我找到了一个解决这个问题的方法(虽然它可以工作,但看起来确实很粗糙)

首先,我创建了一个帮助器类来检查URL是否可访问:

public final class UrlAuthorization {
    private static final Logger LOG = LoggerFactory.getLogger(UrlAuthorization.class);

    private final FilterInvocationSecurityMetadataSource securityMetadataSource;
    private final AccessDecisionManager accessDecisionManager;

    public UrlAuthorization(FilterInvocationSecurityMetadataSource securityMetadataSource,
                            AccessDecisionManager accessDecisionManager) {

        this.securityMetadataSource = securityMetadataSource;
        this.accessDecisionManager = accessDecisionManager;
    }

    public boolean isAccessible(String url) {
        Authentication authentication = AuthUtils.getAuthentication();

        FilterInvocation invocation = new FilterInvocation(null, url, HttpMethod.GET.name());
        Collection<ConfigAttribute> attributes = securityMetadataSource
                .getAttributes(invocation);

        try {
            this.accessDecisionManager.decide(authentication, invocation, attributes);

        } catch (AccessDeniedException e) {
            LOG.trace("Not allowed to access URL: {}", url, e);
            return false;
        }
        return true;
    }
}
最后,我可以这样使用它:

assert urlAuthorization.isAccessible("/accounts") == false;
assert urlAuthorization.isAccessible("/") == true;

通过访问SpringSecurity的内部过滤器,我找到了一个解决这个问题的方法(虽然它可以工作,但看起来确实很粗糙)

首先,我创建了一个帮助器类来检查URL是否可访问:

public final class UrlAuthorization {
    private static final Logger LOG = LoggerFactory.getLogger(UrlAuthorization.class);

    private final FilterInvocationSecurityMetadataSource securityMetadataSource;
    private final AccessDecisionManager accessDecisionManager;

    public UrlAuthorization(FilterInvocationSecurityMetadataSource securityMetadataSource,
                            AccessDecisionManager accessDecisionManager) {

        this.securityMetadataSource = securityMetadataSource;
        this.accessDecisionManager = accessDecisionManager;
    }

    public boolean isAccessible(String url) {
        Authentication authentication = AuthUtils.getAuthentication();

        FilterInvocation invocation = new FilterInvocation(null, url, HttpMethod.GET.name());
        Collection<ConfigAttribute> attributes = securityMetadataSource
                .getAttributes(invocation);

        try {
            this.accessDecisionManager.decide(authentication, invocation, attributes);

        } catch (AccessDeniedException e) {
            LOG.trace("Not allowed to access URL: {}", url, e);
            return false;
        }
        return true;
    }
}
最后,我可以这样使用它:

assert urlAuthorization.isAccessible("/accounts") == false;
assert urlAuthorization.isAccessible("/") == true;

如果使用这种方法,我必须在每个URL之前执行此检查(在显示特定URL之前检查用户是否具有角色)。此外,如果我使用此方法,我将不得不将每个URL与特定角色关联,而我已经通过权威机构在
WebSecurityConfig
中这样做了。还要记住,我不是在使用角色,而是在使用权限。所以这种方法对我不起作用。理想情况下,我需要类似于
webinvocationprivilegeeevaluator.isAllowed(url)
的东西。我猜它应该可以工作,尽管它似乎总是返回
true
,不管我为这个方法提供了什么参数。如果我使用这种方法,我必须在每个URL之前执行这个检查(在显示特定URL之前检查用户是否有角色)。此外,如果我使用此方法,我将不得不将每个URL与特定角色关联,而我已经通过权威机构在
WebSecurityConfig
中这样做了。还要记住,我不是在使用角色,而是在使用权限。所以这种方法对我不起作用。理想情况下,我需要类似于
webinvocationprivilegeeevaluator.isAllowed(url)
的东西。我猜它应该可以工作,尽管它似乎总是返回
true
,而不管我为这个方法提供了什么参数。这可能是个好主意,但对@PreAuthorize不起作用。我得到的FilterSecurityInterceptor只返回带有“authenticated”筛选器的securityMetaDataSource,而所讨论的URL具有@PreAuthorize(“hasRole('ADMIN'))注释。看起来我必须使用不同的过滤器来提供PreAuthorizegreat idea中列出的所有条件,但对@PreAuthorize不起作用。我得到的FilterSecurityInterceptor只返回带有“authenticated”筛选器的securityMetaDataSource,而所讨论的URL具有@PreAuthorize(“hasRole('ADMIN'))注释。看起来我必须使用不同的过滤器来提供预授权中列出的所有条件