Spring Security对Android客户端如何实现权限管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Security对Android客户端如何实现权限管理相关的知识,希望对你有一定的参考价值。

服务端使用Spring Security3.X实现Web端的权限管理,可是如何同时实现对Android客户端的权限管理呢?
新手,懂的不多,还望个各位不吝赐教。

后台的东西无论是安卓,ios都差不多的,如果后台用的是Spring+spring mvc +hibernate架构的话,先导入spring security的包进项目,然后编写spring security配置文件(百度上一大堆),如果对安全要求不高,直接全部用默认的类就能实施一个安全登录的东西了,如果有其他要求,就需要自己编写一些类比如过滤器之类的,然后作为一个普通bean使用。记得要在web.xml中包含你的配置文件,若全部使用默认配置,数据库那里的表名、字段名,表单的action属性,账号、密码的name属性都有要求(是一个定值),要注意。全部都是本人在使用spring security时候的一点小经验,望采纳追问

感谢回答!!!

使用Spring Security 对Web端的权限控制已经实现,我的疑问点是如何实现对客户端(安卓、iOS)的权限控制?

参考技术A 一种是全部利用配置文件,将用户、权限、资源(url)硬编码在xml文件中,已经实现过,并经过验证;
二种是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置,目前这种方式已经实现,并经过验证。
三种是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器,
并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。
目前这种方式已经实现,并经过验证。
四是修改spring security的源代码,主要是修改InvocationSecurityMetadataSourceService和UserDetailsService两个类。
前者是将配置文件或数据库中存储的资源(url)提取出来加工成为url和权限列表的Map供Security使用,后者提取用户名和权限组成一个完整的(UserDetails)User对象,该对象可以提供用户的详细信息供AuthentationManager进行认证与授权使用。

Spring Security 5.1 - 使用 WebClient 获取客户端凭证流的令牌

【中文标题】Spring Security 5.1 - 使用 WebClient 获取客户端凭证流的令牌【英文标题】:Spring Security 5.1 - Get Token for Client Credentials Flow with WebClient 【发布时间】:2019-04-10 23:09:03 【问题描述】:

我正在尝试通过 webclient 获取不记名令牌,并使用以下设置对 servlet 应用程序中的安全资源服务器进行集成测试。

spring:
  security:
    oauth2:
      client:
        registration:
          idp:
            clientId: id
            clientSecret: secret
            authorization-grant-type: client_credentials
            scope: read
        provider:
          idp:
            authorization-uri: myidp/authorization.oauth2
            token-uri: myidp/token.oauth2
            user-info-uri: myidp/userinfo.openid
            user-name-attribute: name

还有豆子,

    @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) 
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
        // oauth.setDefaultOAuth2AuthorizedClient(true);
        // (optional) set a default ClientRegistration.registrationId
        // oauth.setDefaultClientRegistrationId("client-registration-id");
        return WebClient.builder().apply(oauth.oauth2Configuration()).build();
    

并将 web 客户端自动装配到测试并像这样调用它,

webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("idp")).retrieve()
                .bodyToMono(String.class).block();

我的假设是交换函数要么获取访问令牌(如果可用),要么调用从 IDP 获取新令牌。但是它总是会失败,因为HttpSessionOAuth2AuthorizedClientRepository 因为HttpServletRequest 为空。

整体测试看起来像这样,这将提供给自动配置,以便为 IDP 提供者配置一些 bean。

@SpringBootTest(classes = WebITApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
@ActiveProfiles("web-it")
class WebJwtIt 

    @LocalServerPort
    private int port;

    @Autowired
    private WebClient webClient;

    @Test
    void testIdpJwt() 

        String response = webClient.get().uri("http://localhost:" + port + "/web/it")
                .attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId("ping")).retrieve()
                .bodyToMono(String.class).block();
        assertThat(response).isEqualTo("pass");
    

    @RestController
    @SpringBootApplication
    @ImportAutoConfiguration(IdpAutoConfiguration.class)
    static class WebITApplication implements IdpSecurityAdapter 

              @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) 
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
        // oauth.setDefaultOAuth2AuthorizedClient(true);
        // (optional) set a default ClientRegistration.registrationId
        // oauth.setDefaultClientRegistrationId("client-registration-id");
        return WebClient.builder().apply(oauth.oauth2Configuration()).build();
    
        public static void main(String args[]) 

            new SpringApplicationBuilder().profiles("web-it").build().run(WebITApplication.class, args);
        

        @GetMapping
        public String secured() 
            return "secured";
        

        @GetMapping("/web/it")
        public String securedOne() 
            return "pass";
        

        @Override
        public void configure(final HttpSecurity httpSecurity) throws IdpSecurityAdapterException 
            try 
                httpSecurity.oauth2Client();
             catch (Exception e) 
                throw new IdpSecurityAdapterException("Failed to Configure Oauth2Client", e);
            
        

        @Override
        public IdpProvider getIdpProvider() 
            return IdpProvider.MyIdp;
        
    

无论如何,网络客户端是否可以为我获取令牌并将其添加到请求中?我知道spring-security-oauth:OAuthRestTemplate 可以做到这一点,并且阅读了我认为通过网络客户端可以做到的文档。

【问题讨论】:

【参考方案1】:

这里的问题是您没有以正确的方式实例化您的 WebClient。

由于您在客户端,您无权访问OAuth2AuthorizedClientRepository。该 bean 应该链接到您使用 HttpSecurityconfiguration 上的 .oauth2Login() 方法声明登录的资源服务器。这些细节在这里解释:Spring Security 5 Oauth2 Login。

同样,您在客户端,因此您需要一个交换过滤器功能,该功能将触发对授权服务器的请求以获取 JWT 令牌。您可以改用ServerOAuth2AuthorizedClientExchangeFilterFunction

您最好使用WebClientCustomizer 在 WebClient 过滤器中添加交换过滤器功能。为什么 ?仅仅因为在您的 Spring 应用程序中注入 WebClient.Builder 将允许您访问链接到 Web 交换的本机指标。

因此,您将使用UnAuthenticatedServerOAuth2AuthorizedClientRepository bean 的新实例来构建您的 WebClient,如下所示:

// Use injection to get an in-memory reposiroty or client registrations
@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrations) 

    // Provides support for an unauthenticated user such as an application
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());

    // Build up a new WebClientCustomizer implementation to inject the oauth filter
    // function into the WebClient.Builder instance
    return new WebClientSecurityCustomizer(oauth);

由于您在客户端,您没有将用户关联到您的流程,这就是为什么您不能使用任何授权的客户端存储库 bean 实例化。查看 Spring Security 文档:Spring Security documentation : Class UnAuthenticatedServerOAuth2AuthorizedClientRepository。

我尝试在以下GitHub项目中总结一个演示案例:GitHub - Spring Security OAuth2 Machine-To-Machine scenario。

我希望这能让您对 WebClient 配置有更多的了解。如果您有任何问题,请询问。

【讨论】:

这太棒了,到现在一定错过了这个回复! 如果您在 Servlet 环境中的后台线程/非 http 线程中,只想为任何读者添加 ***.com/questions/55308918/… 也应该清楚这一点。使用 Spring Security 5.2 可以使用适当的配置。 我的 Web 客户端有问题,它会在调用资源服务器之前为每个请求获取一个访问令牌。你已经测试了吗? 很好的解释:)

以上是关于Spring Security对Android客户端如何实现权限管理的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Security 保护对 Spring MVC REST API 的 jQuery 调用

Spring Security 5.1 - 使用 WebClient 获取客户端凭证流的令牌

Spring Security OAuth 2.0 - 授权代码授予始终需要客户端密码

Spring security 自定义身份验证提供程序总是导致错误的客户端凭据

开启 Spring Security 时创建 WebSocket 连接失败

使用 REST Web 服务登录 Spring Security