Spring Security自定义FilterInvocationSecurityMetadataSource实现403禁止发布 [英] Spring security custom FilterInvocationSecurityMetadataSource implementation 403 forbidden issue

查看:369
本文介绍了Spring Security自定义FilterInvocationSecurityMetadataSource实现403禁止发布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

To make things short I'm trying to implement a custom FilterInvocationSecurityMetadataSource in order to secure/authorize certain parts/URL endpoints dynamically in my web app using spring security 5.0.6 and Spring Boot 2.0.3.

问题在于,无论我使用什么角色,它始终会为我提供禁止访问的页面.

The issue is that no matter what Role I use it always gives me the forbidden page.

我尝试了几种具有不同角色名称的方法,并且(相信我)即使在Spring Security 5.0.6书籍上,我也搜索了整个互联网,但是似乎没有任何作用.

I have tried several things with different role names and (believe me) I have searched the whole internet even on spring security 5.0.6 books but nothing seems to work.

此问题可能与此类似:动态地保护URL的Spring Security问题

This issue may be similar to this: Spring Security issue with securing URLs dynamically

自定义FilterInvocationSecurityMetadataSource的相关部分之下

Below the relevant parts of the custom 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的自定义实现的相关部分下方

Below the relevant parts of the custom implementation of 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();
}

有关自定义用户详细信息权限的相关部分下面. 用户的角色是:数据库中的ROLE_ADMIN.

Below the relevant parts for custom userDetails authorities. The user has the role: ROLE_ADMIN in database.

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安全授权的动态部分. 谢谢!

What am I doing wrong??
If more code is needed just comment below.
If you have even good books where I can learn this dynamic part of Spring security authorization comment below. Thanks!

推荐答案

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

I managed to get into the security flow by debugging and it seems that by creating ConfigAttributes of this SecurityConfig class is the 'culprit'

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;
}

上面是该方法的实际实现,您可以在其中看到

Above is the actual implementation of the method where you can see

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

这总是创建SecurityConfig类型的实例.

And this always creates an instance of SecurityConfig type.

在下面,您实际上可以看到在哪里以及如何做出决定.

And below you can actually see where and how the decision is being made.

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类型,因此永远不会如此

So in order for it to actually return a configattribute for checking it must be of type WebExpressionConfigAttribute which is never going to be the case because of this

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

所以我要解决的方法是按照以下方式创建自己的accessDecisionManager

So the way I fixed it is to create my own accessDecisionManager the following way

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

And registering as above now setting the accessdecisionManager with my custom one

.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;
        }

这篇关于Spring Security自定义FilterInvocationSecurityMetadataSource实现403禁止发布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆