为每个端点 Spring MVC 指定不同的(基本)身份验证登录

Posted

技术标签:

【中文标题】为每个端点 Spring MVC 指定不同的(基本)身份验证登录【英文标题】:Specify different (basic) authentication log-in per endpoint Spring MVC 【发布时间】:2022-01-09 21:42:50 【问题描述】:

想象以下(假设的)数据结构

endpoint | username | password
users      admin      123
info       george     awd
data       magnus     e4

这意味着每个端点都需要不同的凭据,并且没有一个用户名/密码组合可以登录到每个端点。在添加更多端点时,我正在寻找一种在我们的 Spring MVC 项目中使其可扩展的方法。我们可以使用角色并将其硬核到配置类中,但端点和登录组合因每个客户安装而异

鉴于以下 SecurityConfiguration 和 LookupAuthenticationService 是在数据库中查找用户名/密码数据的类

@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    private static final String[] ENDPOINT_LIST = 
        "/rest/**"
    ;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
                .authorizeRequests()
                .antMatchers(ENDPOINT_LIST)
                .authenticated()
                .and()
                .httpBasic();
    

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.authenticationProvider(authenticationProvider());
    

    @Bean
    public DaoAuthenticationProvider authenticationProvider() 
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService());
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    

    @Bean
    public PasswordEncoder passwordEncoder() 
        return new BCryptPasswordEncoder();
    

    @Override
    protected UserDetailsService userDetailsService() 
        return new LookupAuthenticationService(passwordEncoder());
    

理想的情况是 LookupAuthenticationService 可以访问请求,因此我们知道要获取哪个端点,但我想这只有在使用单个过滤器时才有可能

目前我发现的可能性是:

为每个端点添加一个 WebSecurityConfigurerAdapter 和多个特定的 UserDetailsS​​erver -> 大量代码 为每个端点添加一个 HandlerInterceptor -> 大量代码 AuthenticationManagerResolver 根据 pathInfo 返回不同的 AuthenticationManager?

任何关于如何最好地解决此问题的意见将不胜感激

【问题讨论】:

endpoint 只是一个权限,只是添加规则,用于 url 映射和权限。 1 个配置已解决。 你能详细说明一下这个@M.Deinum 吗? 您可以编写一个用户查询,将endpoint 列映射到用户的权限/角色。然后,您可以为给定权限添加 url/endpoints 的安全性。 【参考方案1】:

您可以有一个表,您可以在其中将端点映射到规则,如下所示:

pattern authority
/users/** ROLE_ADMIN
/info/** ROLE_USER
/another/** ROLE_ANOTHER

您无需将用户分配给端点,而是将角色分配给用户。有了这个,您可以创建一个AuthorizationManager,它将根据请求路径保护您的端点。

@Component
public class AccessRuleAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> 

    private final AccessRuleRepository rules;
    private RequestMatcherDelegatingAuthorizationManager delegate;

    public AccessRuleAuthorizationManager(AccessRuleRepository rules) 
        this.rules = rules;
    

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) 
        return this.delegate.check(authentication, object.getRequest());
    

    @EventListener
    void applyRules(ApplicationReadyEvent event) 
        Builder builder = builder();
        for (AccessRule rule : this.rules.findAll()) 
            builder.add(
                    new AntPathRequestMatcher(rule.getPattern()),
                    AuthorityAuthorizationManager.hasAuthority(rule.getAuthority())
            );
        
        this.delegate = builder.build();
    

而且,在您的 SecurityConfiguration 中,您只需执行以下操作:

@Autowired
private AccessRuleAuthorizationManager access;

@Override
protected void configure(HttpSecurity http) throws Exception 
    http
            .authorizeHttpRequests((authz) -> 
                authz.anyRequest().access(this.access)
           )
           .httpBasic(Customizer.withDefaults());

我建议您查看this repository 并观看存储库描述中的演示文稿。演示文稿的最后一步是添加自定义 AuthorizationManager,对此有很好的解释。

【讨论】:

感谢您的广泛回复,它帮助我深入了解我真正想问的问题。我可能会删除这个问题,因为它没有多大意义。不幸的是,在我们的系统中,用户不是传统用户,可以使用相同的用户名但使用不同的密码定义多个用户 - 不允许我为单个用户设置角色。我需要一种更即时的方式来处理 UserDetailsS​​ervice/loadUserByUsername 不允许的事情

以上是关于为每个端点 Spring MVC 指定不同的(基本)身份验证登录的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot之执行器端点(Actuator Endpoint)实现剖析

Spring Security + MVC:相同的@RequestMapping,不同的@Secured

如何正确计时用 Java Spring MVC 编写的 API?

Spring MVC的常用注解

Spring MVC Controller中JsonView的动态选择

在 Kestrel 上为 ASP.NET Core 上的两个不同端点发布两个不同的端点