spring security OAuth2 - 自定义 ClientDetailsS​​ervice

Posted

技术标签:

【中文标题】spring security OAuth2 - 自定义 ClientDetailsS​​ervice【英文标题】:spring security OAuth2 - custom ClientDetailsService 【发布时间】:2017-04-13 10:59:57 【问题描述】:

我目前正在开发用于 Oauth2 身份验证的 spring 应用程序,但在实现自定义 ClientDetailsS​​ervice 时遇到了一些问题。

我无法使用常见的 inMemory 或 jdbc clientDetailsS​​ervice,因为客户端信息没有存储在我的应用程序中,我从外部 Web 服务获取它们。但是,当我设置自定义 ClientDetailService 时,我不再获得 access_confirmation 页面(我得到一个空白页面)。

为了向您展示我的问题,我不使用我的应用程序,而是使用官方 spring--security-oauth 项目 spring-security-oauth 的 vanilla 测试

这是应用程序代码:

@SpringBootApplication
@EnableResourceServer
@RestController
public class Application 

    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    

    @RequestMapping("/")
    public String home() 
        return "Hello World";
    

    @RequestMapping(value = "/", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public String create(@RequestBody MultiValueMap<String, String> map) 
        return "OK";
    

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter 

        @Autowired
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
            endpoints.authenticationManager(authenticationManager);
        

        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception 
            security.checkTokenAccess("isAuthenticated()");
        

        public ClientDetailsService clientDetailsService() 
            return new ClientDetailsService() 
                @Override
                public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException 
                    BaseClientDetails details = new BaseClientDetails();
                    details.setClientId(clientId);
                    details.setAuthorizedGrantTypes(Arrays.asList("authorization_code") );
                    details.setScope(Arrays.asList("read, trust"));
                    details.setResourceIds(Arrays.asList("oauth2-resource"));
                    Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
                    authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT"));
                    details.setAuthorities(authorities);
                    return details;
                
            ;
          //*/


        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
            // @formatter:off

            clients.withClientDetails(clientDetailsService());

            /*clients.inMemory()
                .withClient("test")
                    .authorizedGrantTypes("authorization_code")
                    .authorities("ROLE_CLIENT")
                    .scopes("read", "trust")
                    .resourceIds("oauth2-resource");
            //*/
            // @formatter:on
        
    


如您所见,我添加了我的自定义 clientDetailsS​​ervice 并更改了 ClientDetailsS​​erviceconfigurer 配置以设置它而不是内存中的 clientDetailsS​​ervice。

我的问题是,当我尝试获取我的令牌时,我在登录用户后不再获得我的 access_confirmation 页面。

我发现了我的问题,我在 clientDetails 中对范围的定义是错误的。我有 Arrays.asList("read, trust") 而不是 Arrays.asList("read", "trust")

我错过了什么吗?我必须在其他地方设置我的自定义 clientDetailsS​​ervice 吗?

【问题讨论】:

您是否有其他信息(如堆栈跟踪或日志)可以显示有关您的问题的更多信息? 我的测试没有任何错误。如果我尝试使用邮递员设置获取令牌 - localhost:8080/oauth/authorize 作为授权 url - localhost:8080/oauth/token 作为令牌 url - 测试作为客户端 id - authentication_code 作为授权类型我在用户之后得到一个空屏幕身份验证(他没有进入 confirm_access 页面) 如果我在我的浏览器上用这个 url 测试它:localhost:8080/oauth/… 我被重定向到 redirect-uri 而没有获得 confirm_access 页面(对于浏览器 url,我知道 url 不正确获取我的令牌,但它应该足以测试授权) 如果您在 ClientDetails 中定义重定向 uri,如 details.setRegisteredRedirectUri(...) 会怎样? 我试过了,但它没有改变,registeredRedirectUris 没有在正在工作的 inMemory clientDetailsS​​ervice 定义中定义 【参考方案1】:

我正在尝试做类似的事情,但我有一些不同的问题。希望你们能在这里帮助我。

我下面有一门课

@Entity
@Table(name = "oauth_client_details")
public class CustomOAuthClientDetails extends BaseClientDetails
    
    
    
    /**
     * 
     */
    private static final long serialVersionUID = -2792747663814219416L;

    @Id
    @Override
    public String getClientId() 
        return super.getClientId();
    
    
    
    @Override
    public String getClientSecret() 
        return super.getClientSecret();
    
    
    @Override
    public Collection<GrantedAuthority> getAuthorities() 
        return super.getAuthorities();
    


如下声明的存储库类

Optional<CustomOAuthClientDetails> customOAuthClientDetails = authClientDetailsRepository.findByClientId(clientId);

当我尝试像下面那样做时

details.setAuthorizedGrantTypes(customOAuthClientDetails.get().getAuthorizedGrantTypes());

我遇到错误

Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: oauth_client_details, for columns: [org.hibernate.mapping.Column(authorities)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:499) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:466) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.Property.isValid(Property.java:227) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:624) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.mapping.RootClass.validate(RootClass.java:267) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:354) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) ~[hibernate-core-5.4.26.Final.jar:5.4.26.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.2.jar:5.3.2]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.2.jar:5.3.2]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.2.jar:5.3.2]
    ... 21 common frames omitted


【讨论】:

我可以分析的问题是我无法将 oauth_client_details 表中的数据解析到我的实体类。我该怎么做? 欢迎来到 SO。请仅将答案部分用于实际回答。如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。【参考方案2】:

尝试像这样更改您的 ClientDetails impl:

public ClientDetailsService clientDetailsService() 
        return new ClientDetailsService() 
            @Override
            public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException 
                BaseClientDetails details = new BaseClientDetails();
                details.setClientId(clientId);
                details.setAuthorizedGrantTypes(Arrays.asList("authorization_code") );
                details.setScope(Arrays.asList("read, trust"));
                details.setRegisteredRedirectUri(Collections.singleton("http://anywhere.com"));
                details.setResourceIds(Arrays.asList("oauth2-resource"));
                Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
                authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT"));
                details.setAuthorities(authorities);
                return details;
            
        ;
      //*/

【讨论】:

感谢您的帮助,我发现我的错误是我在客户详细信息中对范围的定义是错误的。我有 Arrays.asList("read, trust") 而不是 Arrays.asList("read", "trust") 不错!没有注意到我 c/p 的错字:)

以上是关于spring security OAuth2 - 自定义 ClientDetailsS​​ervice的主要内容,如果未能解决你的问题,请参考以下文章

Spring-Security OAuth2 设置 - 无法找到 oauth2 命名空间处理程序

Spring Security OAuth2 v5:NoSuchBeanDefinitionException:'org.springframework.security.oauth2.jwt.Jwt

如何使用spring-security,oauth2调整实体的正确登录?

针对授权标头的Spring Security OAuth2 CORS问题

Spring Security---Oauth2详解

OAuth2.0学习(4-1)Spring Security OAuth2.0 - 代码分析