【问题标题】:Spring security custom FilterInvocationSecurityMetadataSource implementation 403 forbidden issueSpring security自定义FilterInvocationSecurityMetadataSource实现403禁止问题
【发布时间】:2018-12-29 14:27:45
【问题描述】:

为了简短起见,我正在尝试实现自定义 FilterInvocationSecurityMetadataSource,以便使用 spring security 5.0.6 和 Spring Boot 2.0.3 在我的 Web 应用程序中动态保护/授权某些部分/URL 端点。

问题是无论我使用什么角色,它总是给我禁止页面。

我已经尝试了几种不同角色名称的东西,并且(相信我)我已经搜索了整个互联网,甚至在 spring security 5.0.6 书籍上,但似乎没有任何效果。

这个问题可能类似这样:Spring Security issue with securing URLs dynamically

下面自定义FilterInvocationSecurityMetadataSource的相关部分

public class DbFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

public Collection<ConfigAttribute> getAttributes(Object object)
        throws IllegalArgumentException {
    FilterInvocation fi=(FilterInvocation)object;
    String url=fi.getRequestUrl();

    System.out.println("URL requested: " + url);

    String[] stockArr = new String[]{"ROLE_ADMIN"};

    return SecurityConfig.createList(stockArr);
}

下面是securitywebconfigAdapter的自定义实现的相关部分

@Configuration
public class Security extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated()
            .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
            public <O extends FilterSecurityInterceptor> O postProcess(
                    O fsi) {
                FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
                fsi.setSecurityMetadataSource(newSource);
                return fsi;
            }
        })
        .and()
        .formLogin()
        .permitAll();
}

在自定义 userDetails 权限的相关部分下方。 用户在数据库中具有角色:ROLE_ADMIN。

public class CustomUserDetails extends User implements UserDetails {

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<String> dbRoles=new ArrayList<String>();
    for (Role userRole : super.getRoles()) {
        dbRoles.add(userRole.getType());
    }

    List<SimpleGrantedAuthority> authorities=new ArrayList<SimpleGrantedAuthority>();
    for (String role : dbRoles) {
        authorities.add(new SimpleGrantedAuthority(role));
    }
    return authorities;
}

我做错了什么??
如果需要更多代码,请在下方评论。
如果你有好书,我可以在下面学习 Spring 安全授权评论的这个动态部分。 谢谢!

【问题讨论】:

    标签: authentication spring-security authorization http-status-code-403 access-denied


    【解决方案1】:

    我设法通过调试进入了安全流程,似乎通过创建此 SecurityConfig 类的 ConfigAttributes 是“罪魁祸首”

    return SecurityConfig.createList(stockArr);
    public static List<ConfigAttribute> createList(String... attributeNames) {
        Assert.notNull(attributeNames, "You must supply an array of attribute names");
        List<ConfigAttribute> attributes = new ArrayList(attributeNames.length);
        String[] var2 = attributeNames;
        int var3 = attributeNames.length;
    
        for(int var4 = 0; var4 < var3; ++var4) {
            String attribute = var2[var4];
            attributes.add(new SecurityConfig(attribute.trim()));
        }
    
        return attributes;
    }
    

    上面是方法的实际实现在哪里可以看到

    attributes.add(new SecurityConfig(attribute.trim()));
    

    这总是会创建一个 SecurityConfig 类型的实例。

    您实际上可以在下面看到决策是在哪里以及如何做出的。

    private WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
        Iterator var2 = attributes.iterator();
    
        ConfigAttribute attribute;
        do {
            if (!var2.hasNext()) {
                return null;
            }
    
            attribute = (ConfigAttribute)var2.next();
        } while(!(attribute instanceof WebExpressionConfigAttribute));
    
        return (WebExpressionConfigAttribute)attribute;
    }
    

    所以为了让它真正返回一个用于检查的配置属性,它必须是 WebExpressionConfigAttribute 类型,因此永远不会出现这种情况

    attributes.add(new SecurityConfig(attribute.trim()));
    

    所以我修复它的方法是通过以下方式创建我自己的 accessDecisionManager

    public class MyAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){
            return  ;
        }
        Iterator<ConfigAttribute> ite = configAttributes.iterator();
        while(ite.hasNext()){
    
            ConfigAttribute ca = ite.next();
    
            String needRole = ((SecurityConfig)ca).getAttribute();
    
            for(GrantedAuthority grantedAuthority : authentication.getAuthorities()){
                if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){
                    return;
                }
            }
        }
        throw new AccessDeniedException("Access is denied");
    }
    

    并像上面一样注册现在使用我的自定义设置 accessdecisionManager

    .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
            public <O extends FilterSecurityInterceptor> O postProcess(
                    O fsi) {
                FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
                fsi.setSecurityMetadataSource(newSource);
                fsi.setAccessDecisionManager(new MyAccessDecisionManager());
                return fsi;
            }
    

    【讨论】:

      猜你喜欢
      • 2020-12-18
      • 2018-12-24
      • 2021-10-01
      • 2017-11-11
      • 2020-07-31
      • 2014-12-01
      • 2015-08-16
      • 2015-07-24
      • 2019-08-22
      相关资源
      最近更新 更多