Já discutimos Como configurar uma autenticação OAuth 2.0 e como criar um armazenamento de token personalizado. No último artigo desta série, você aprenderá a implementar um registro de cliente dinâmico personalizado usando segurança de primavera-oauth2. Eu recomendo que você leia Parte 1 e Parte 2 primeiro, pois vamos continuar de onde paramos.
Vamos começar criando a entidade responsável por armazenar os dados do cliente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
importação com.couchbase.cliente.java.repositório.anotação.Id; importação lombok.Dados; importação lombok.NoArgsConstructor; importação org.estrutura de mola.dados.couchbase.núcleo.mapeamento.Documento; importação javax.validação.restrições.Não nulo; importação java.util.*; @NoArgsConstructor @Data @Documento público classe Detalhes do cliente personalizado se estende BasicEntity { @Id @NotNull privado Cordas id; @NotNull privado Cordas clienteId; privado Cordas clientSecret; privado Conjunto<String> resourceIds = novo HashSet<>(); privado booleano secretRequired; privado booleano com escopo; privado Conjunto<String> escopo = novo HashSet<>(); privado Conjunto<String> authorizedGrantTypes = novo HashSet<>(); privado Conjunto<String> registeredRedirectUri = novo HashSet<>(); privado Coleção<String> autoridades = novo HashSet<>(); privado Inteiro accessTokenValiditySeconds; privado Inteiro refreshTokenValiditySeconds; privado booleano autoAprovar; privado Mapa<Cordas, Objeto> additionalInformation = novo HashMap<>(); } |
Aqui está o respectivo repositório:
1 2 3 4 5 6 7 8 9 10 11 |
importação org.estrutura de mola.dados.couchbase.núcleo.consulta.N1qlPrimaryIndexed; importação org.estrutura de mola.dados.couchbase.núcleo.consulta.ViewIndexed; importação org.estrutura de mola.dados.couchbase.repositório.CouchbasePagingAndSortingRepository; @N1qlPrimaryIndexed @ViewIndexed(designDoc = "customClientDetails") público interface CustomClientDetailsRepository se estende CouchbasePagingAndSortingRepository<Detalhes do cliente personalizado, Cordas> { Detalhes do cliente personalizado findByClientId(Cordas clienteId); } |
Agora, podemos implementar o ClientDetailsService da classe de segurança do Spring:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
importação org.estrutura de mola.feijões.fábrica.anotação.Com fio automático; importação org.estrutura de mola.segurança.oauth2.provedor.ClientDetails; importação org.estrutura de mola.segurança.oauth2.provedor.ClientDetailsService; importação org.estrutura de mola.segurança.oauth2.provedor.ClientRegistrationException; importação org.estrutura de mola.segurança.oauth2.provedor.cliente.BaseClientDetails; importação org.estrutura de mola.estereótipo.Serviço; importação java.util.fluxo.Colecionadores; @Serviço público classe CouchbaseClientDetailsService implementa ClientDetailsService { @Com fio automático privado CustomClientDetailsRepository customClientDetailsRepository; @Substituir público ClientDetails loadClientByClientId(Cordas clienteId) lançamentos ClientRegistrationException { Detalhes do cliente personalizado cliente = customClientDetailsRepository.findByClientId(clienteId); Cordas resourceIds = cliente.getResourceIds().fluxo().coletar(Colecionadores.união(",")); Cordas escopos = cliente.getScope().fluxo().coletar(Colecionadores.união(",")); Cordas grantTypes = cliente.getAuthorizedGrantTypes().fluxo().coletar(Colecionadores.união(",")); Cordas autoridades = cliente.getAuthorities().fluxo().coletar(Colecionadores.união(",")); BaseClientDetails base = novo BaseClientDetails(cliente.getClientId(), resourceIds, escopos, grantTypes, autoridades); base.setClientSecret(cliente.getClientSecret()); base.setAccessTokenValiditySeconds(cliente.getAccessTokenValiditySeconds()); base.setRefreshTokenValiditySeconds(cliente.getRefreshTokenValiditySeconds()); base.setAdditionalInformation(cliente.getAdditionalInformation()); base.setAutoApproveScopes(cliente.getScope()); retorno base; } } |
Observe que estou usando o BaseClientDetails em vez de implementar a classe ClientDetails interface. Essa parece ser a melhor opção, pois até mesmo a implementação padrão do JDBC a utiliza.
Por fim, precisamos alterar nosso AuthorizationServerConfig para usar nosso CouchbaseClientDetailsService:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Configuração @EnableAuthorizationServer público classe AuthorizationServerConfig se estende AuthorizationServerConfigurerAdapter { @Autowired privado CouchbaseClientDetailsService couchbaseClientDetailsService; @Override público vazio configurar(ClientDetailsServiceConfigurer configurador) lançamentos Exceção { configurador.comClientDetails(couchbaseClientDetailsService); } } |
Esta é a aparência da classe inteira:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
importação org.estrutura de mola.feijões.fábrica.anotação.Com fio automático; importação org.estrutura de mola.contexto.anotação.Configuração; importação org.estrutura de mola.segurança.autenticação.Gerenciador de autenticação; importação org.estrutura de mola.segurança.criptografia.senha.PasswordEncoder; importação org.estrutura de mola.segurança.oauth2.configuração.anotação.configuradores.ClientDetailsServiceConfigurer; importação org.estrutura de mola.segurança.oauth2.configuração.anotação.web.configuração.AuthorizationServerConfigurerAdapter; importação org.estrutura de mola.segurança.oauth2.configuração.anotação.web.configuração.EnableAuthorizationServer (Ativar servidor de autorização); importação org.estrutura de mola.segurança.oauth2.configuração.anotação.web.configuradores.AuthorizationServerEndpointsConfigurer; importação org.estrutura de mola.segurança.oauth2.configuração.anotação.web.configuradores.AuthorizationServerSecurityConfigurer; importação org.estrutura de mola.segurança.oauth2.provedor.token.TokenStore; @Configuração @EnableAuthorizationServer público classe AuthorizationServerConfig se estende AuthorizationServerConfigurerAdapter { @Autowired privado TokenStore tokenStore; @Autowired privado Gerenciador de autenticação gerenciador de autenticação; @Autowired privado CouchbaseClientDetailsService couchbaseClientDetailsService; @Autowired privado PasswordEncoder passwordEncoder; @Override público vazio configurar(ClientDetailsServiceConfigurer configurador) lançamentos Exceção { configurador.comClientDetails(couchbaseClientDetailsService); } @Override público vazio configurar(AuthorizationServerEndpointsConfigurer pontos finais) lançamentos Exceção { pontos finais.tokenStore(tokenStore) .gerenciador de autenticação(gerenciador de autenticação); } @Override público vazio configurar( AuthorizationServerSecurityConfigurer oauthServer) lançamentos Exceção { oauthServer .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } } |
Agora você pode simplesmente inserir um novo cliente em seu banco de dados e usar essas credenciais para autenticar via OAuth:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
estático final Cordas GRANT_TYPE_PASSWORD = "senha"; estático final Cordas AUTHORIZATION_CODE = "authorization_code"; estático final Cordas REFRESH_TOKEN = "refresh_token"; estático final Cordas IMPLÍCITO = "implícito"; estático final Cordas SCOPE_READ = "ler"; estático final Cordas SCOPE_WRITE = "escrever"; estático final Cordas CONFIANÇA = "confiança"; privado vazio createOauthClients() { Detalhes do cliente personalizado cliente = novo Detalhes do cliente personalizado(); cliente.setId("someId"); cliente.setResourceIds(novo HashSet<>(Matrizes.asList("resource_id")) ); cliente.setClientId("android-client"); cliente.setClientSecret("android-secret"); cliente.setAuthorizedGrantTypes(novo HashSet<>(Matrizes.asList(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLÍCITO))); cliente.setScope(novo HashSet<>(Matrizes.asList(SCOPE_READ, SCOPE_WRITE, CONFIANÇA))); cliente.setSecretRequired(verdadeiro); cliente.setAccessTokenValiditySeconds(50000); cliente.setRefreshTokenValiditySeconds(50000); cliente.setScoped(falso); customClientDetailsRepository.salvar(cliente); } |
TL;DR - O truque é implementar o org.springframework.security.oauth2.provider.ClientDetailsService e passá-la como um parâmetro para sua interface ClientDetailsServiceConfigurer:
1 2 3 4 |
@Override público vazio configurar(ClientDetailsServiceConfigurer configurador) lançamentos Exceção { configurador.comClientDetails(couchbaseClientDetailsService); } |
Se você tiver alguma dúvida, envie-me um tweet para @deniswsrosa