【问题标题】:Multiple authenticationProvider in MicronautMicronaut 中的多个 authenticationProvider
【发布时间】:2020-06-01 10:58:33
【问题描述】:

是否可以在 Micronaut 中定义多个 authenticationProviders

假设我有一个 entity A,可以使用 authenticationProviderA 进行记录:它给了一个用户并通过了检查 A 的 DB 表 .

是否可以添加一个 entity B 及其 authenticationProviderB 给用户并通过将检查 B 的 DB 表? 如果是这样,你如何在你的控制器中定义你想使用哪个authenticationProvider

【问题讨论】:

    标签: java micronaut


    【解决方案1】:

    查看 io.micronaut.security.authentication.Authenticator 后,我发现在 Micronaut 中可以有多个 authenticationProviders

    文档说:

    Authenticator 对多个 {@link AuthenticationProvider} 实例进行操作,返回第一个经过身份验证的 {@link AuthenticationResponse}

    据我所知,您只需要实现 AuthenticationProvider 并且 Authenticator 将在 AuthenticationProviders 的内部列表中包含实现(即使它没有注释!)。

    恕我直言,这不是提供多种身份验证方式的好方法。在问题中提供的示例中,A 和 B 的身份验证都需要调用 DB,这意味着将执行 AuthenticationProviders 不需要的 BD 调用的执行顺序。

    我认为最好提供一种方法来指示控制器或端点必须使用哪个AuthenticationProviders。 也许有办法做到这一点,我只是不知道,如果有,请随时发表评论。

    【讨论】:

    • 您可以在任何不应该用于对给定用户进行身份验证的身份验证提供程序中简单地返回空
    • " 将包括实现(即使它没有注释!) " 这不是真的。任何注入 Authenticator 的类都必须是 bean。
    • 您如何知道在给定凭据的情况下应该使用哪种身份验证?在其他框架中,提供使用的身份验证由路径定义。使用 Micronaut,您只有确定要使用哪个身份验证提供程序的凭据,对吗?如果是这样,我看不出您如何确定要使用的身份验证提供程序。关于包含的实现我会再次测试,以防万一。
    • 当我从命令行(使用 mvn)执行测试而没有缺少身份验证提供程序的 @Singleton 注释时,“任何注入的类都必须是 bean”是正确的。由于某种我仍然不知道的原因,IDE 的行为有所不同,因为在使用 IntelliJ 进行调试时,我检查了即使没有注释也调用了构造函数
    【解决方案2】:

    没有针对该问题的内置解决方案,但有多种方法可以用少量代码实现您想要的。

    解决方案№1: 如果您需要多个登录端点,请创建自定义 AuthenticationRequest.classLoginController.class

    public class AuthenticationRequestForEntityA extends UsernamePasswordCredentials { ... }

    public class AuthenticationRequestForEntityB extends UsernamePasswordCredentials { ... }

    在您的自定义LoginController 中,将默认UsernamePasswordCredentials 替换为您的特定AuthenticationRequestForEntityAAuthenticationRequestForEntityB,然后复制粘贴原始LoginController.class 中的其余代码:

        @Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON})
        @Post
        public Single<MutableHttpResponse<?>> login(@Valid @Body AuthenticationRequestForEntityA usernamePasswordCredentials, HttpRequest<?> request) {
            Flowable<AuthenticationResponse> authenticationResponseFlowable = Flowable.fromPublisher(authenticator.authenticate(request, usernamePasswordCredentials));
            ...
    

    然后在您的身份验证提供程序中:

    public class AuthenticationProviderA implements AuthenticationProvider {
    
        @Override
        public Publisher<AuthenticationResponse> authenticate(@Nullable HttpRequest<?> httpRequest, AuthenticationRequest<?, ?> authenticationRequest) {
    
           if (authenticationRequest instanceof AuthenticationRequestForEntityA) {
               return authenticate(authenticationRequest);
           } else {
               // return empty
           }
        }
    
    }
    
    
    public class AuthenticationProviderB implements AuthenticationProvider {
    
        @Override
        public Publisher<AuthenticationResponse> authenticate(@Nullable HttpRequest<?> httpRequest, AuthenticationRequest<?, ?> authenticationRequest) {
    
           if (authenticationRequest instanceof AuthenticationRequestForEntityB) {
               return authenticate(authenticationRequest);
           } else {
               // return empty
           }
        }
    
    }
    

    解决方案№2:创建基于自定义路由的AuthenticationProvider

    由于HttpRequestAuthenticationProvider 中作为输入参数可用,您可以简单地根据httpRequest 路径或查询参数属性进行身份验证。 为了使代码更简洁,您可以创建自己的RouteBasedAuthenticationProvider 接口:

    public interface RequestBasedAuthenticationProvider extends AuthenticationProvider {
      
      /**
        You can check the request path or request parameter or whatever
      */
      boolean supports(HttpRequest<?> request);
    }
    
    

    然后在 Micronaut AuthenticationProvider:

    @Context
    public class AppAuthenticationProvider implements AuthenticationProvider {
    
        private final Collection<RequestBasedAuthenticationProvider> providers;
    
        constructor(...) {...} 
    
        @Override
        public Publisher<AuthenticationResponse> authenticate(@Nullable HttpRequest<?> httpRequest, AuthenticationRequest<?, ?> authenticationRequest) {
    
           return providers.stream()
               .filter(provider -> provider.supports(httpRequest))
               .findFirst()
               .orElseThrow(//Throw provider not found error)
               .authenticate(httpRequest, authenticationRequest);
    
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    • 2019-05-23
    • 2020-01-10
    相关资源
    最近更新 更多