В Spring Security (Spring Boot 2.x), как мне предоставить собственную реализацию для @ Pre / PostAuthorize и проверки ролей? - PullRequest
0 голосов
/ 20 декабря 2018

Я хочу использовать встроенные аннотации Spring @PreAuthorize и hasRole, hasAnyRole и т. Д., Но классы Spring вызывают мою реализацию, чтобы определить, должно ли это быть true / false.Как мне это сделать?

Есть ли в * 1006 конфигурация, которую я могу переопределить?

Нужно ли реализовать класс SecurityExpressionRoot?И если да, то где мне сказать, чтобы он использовал мой?

Я попытался переопределить диспетчер принятия решений о доступе и добавить своего собственного избирателя, но даже если он вызывает мой метод, и я возвращаю true (и это AffirmativeBased менеджер), он все равно переходит к SecurityExpressionRoot.hasAnyRole(), который затем возвращает false.

public class MyDecisionVoter implements AccessDecisionVoter<Object>
{
    @Override
    public boolean supports(ConfigAttribute attribute)
    {
        //We want to always be called
        return true;
    }


    @Override
    public boolean supports(Class<?> clazz)
    {
        //We want to always be called
        return true;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes)
    {
        //For testing purposes
        return ACCESS_GRANTED;
    }
}

Диспетчер

public class MyAffirmativeBasedDecisionManager extends AffirmativeBased
{
    public MyAffirmativeBasedDecisionManager(List<AccessDecisionVoter<?>> decisionVoters)
    {
        super( decisionVoters );
    }

    @Override
    public boolean supports(Class<?> clazz)
    {
        for ( AccessDecisionVoter<?> voter : this.getDecisionVoters() )
        {
            if ( voter.supports( clazz ) )
            {
                return true;
            }
        }

        return false;
    }
}

Настройка

@EnableWebSecurity
@EnableGlobalMethodSecurity( prePostEnabled = true )
public class MyConfig extends WebSecurityConfigurerAdapter
{
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        //Turn on OAuth
        http.authorizeRequests()
            .anyRequest()
            .authenticated()
            .accessDecisionManager( createDecisionManager() );
    }

    private AccessDecisionManager createDecisionManager()
    {
        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();

        ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
        expressionAdvice.setExpressionHandler( new DefaultMethodSecurityExpressionHandler() );

        decisionVoters.add( new MyDecisionVoter() );
        decisionVoters.add( new PreInvocationAuthorizationAdviceVoter( expressionAdvice ) );
        decisionVoters.add( new RoleVoter() );
        decisionVoters.add( new AuthenticatedVoter() );

        return new MyAffirmativeBasedDecisionManager( decisionVoters );
    }
}

Это должно позволитьих, но это не с 403:

@GetMapping( "shouldallow" )
@ResponseBody
@PreAuthorize( "hasRole('ROLE_NOT_EXIST')" )
public String shouldAllow()
{
    return "should allow";
}

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Если вы хотите, чтобы @PreAuthorize("hasRole('USER')") вызывал ваш метод вместо метода в SecurityExpressionRoot, тогда да, вам нужно заменить его, выставив свой MethodSecurityExpressionHandler в качестве компонента.Вы бы переопределили его createSecurityExpressionRoot метод:

class MyExpressionHandler extends DefaultMethodSecurityExpressionHandler {
    @Override
    protected MethodSecurityExpressionOperations
        createSecurityExpressionRoot(Authentication a, MethodInvocation mi) {
        return new MyRoot(super.createSecurityExpressionRoot(a, mi));
    }
}

@EnableGlobalMethodSecurity(prePostEnabled=true)
class UsingCustomExpressionHandler extends GlobalMethodSecurityConfiguration {
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new MyExpressionHandler();
    }
}

НО , есть менее инвазивные вещи, которые вы можете попробовать сначала.

Использование компонента

Например, вы можете обращаться к любому из ваших собственных bean-компонентов внутри SpEL .Итак, если вы создали @Bean, который может выполнять оценку, вам не нужно вызывать hasRole.Вместо этого вы можете просто:

@PreAuthorize("@myBean.evaluate(authentication)")

Это дает вам большую гибкость, чтобы делать все, что вам нужно делать с Authentication для определения доступа.

Mapping Authorities

Или вы можете сопоставить все, что у вас есть в виде пользовательских ролей, с набором GrantedAuthority s.Некоторые механизмы аутентификации в Spring Security предоставляют способ сопоставления пользовательских представлений прав доступа.

Например, я заметил ваш комментарий // turn on OAuth.Если вы хотите переопределить hasRole из-за областей OAuth, вы можете использовать oauth2ResourceServer() и , предоставив пользовательские JwtAuthenticationConverter, чтобы адаптировать ваши пользовательские права доступа к GrantedAuthority s.В этом случае hasRole может не потребоваться переопределять вообще.(Конечно, я не знаю, какова ваша конкретная ситуация в отношении того, как вы аутентифицируете пользователя. Это только один из примеров GrantedAuthority преобразования среди многих.)

0 голосов
/ 20 декабря 2018

Может помочь:

public class AuthorizationService {

public boolean hasAccess(Object obj) {
 // your code here
}
}

@GetMapping( "/someurl" )
@PreAuthorize("@authorizationService.hasAccess(#obj)")
public void dummyMethod(@PathVariable("obj") Object obj) {
}

, если вы определяете разрешение на основе какого-либо объекта, вы можете передать его непосредственно методу.В противном случае вы можете игнорировать аргумент в методе hasAccess.И вы должны предоставить bean из AuthorizationService.

...