Ya hemos hablado de cómo configurar una autenticación OAuth 2.0 y cómo crear un almacén de fichas personalizado. En el último artículo de esta serie, aprenderá a implementar un registro de cliente dinámico personalizado utilizando spring-seguridad-oauth2. Le recomiendo que lea Parte 1 y Parte 2 primero, ya que vamos a continuar desde donde lo hemos dejado.
Empecemos por crear la entidad responsable de almacenar los datos del 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 |
importar com.couchbase.cliente.java.repositorio.anotación.Id; importar lombok.Datos; importar lombok.NoArgsConstructor; importar org.springframework.datos.couchbase.núcleo.cartografía.Documento; importar javax.validación.limitaciones.NotNull; importar java.util.*; @NoArgsConstructor @Datos @Documento público clase CustomClientDetails extiende Entidad básica { @Id @NotNull privado Cadena id; @NotNull privado Cadena clientId; privado Cadena clientSecret; privado Establecer<String> resourceIds = nuevo HashSet<>(); privado booleano secretRequired; privado booleano alcance; privado Establecer<String> alcance = nuevo HashSet<>(); privado Establecer<String> authorizedGrantTypes = nuevo HashSet<>(); privado Establecer<String> registeredRedirectUri = nuevo HashSet<>(); privado Colección<String> autoridades = nuevo HashSet<>(); privado Entero accessTokenValiditySeconds; privado Entero refreshTokenValiditySeconds; privado booleano autoAprobar; privado Mapa<Cadena, Objeto> información adicional = nuevo HashMap<>(); } |
Aquí está el repositorio correspondiente:
1 2 3 4 5 6 7 8 9 10 11 |
importar org.springframework.datos.couchbase.núcleo.consulta.N1qlPrimaryIndexed; importar org.springframework.datos.couchbase.núcleo.consulta.VerIndexado; importar org.springframework.datos.couchbase.repositorio.CouchbasePagingAndSortingRepository; @N1qlPrimaryIndexed @VerIndexado(designDoc = "customClientDetails") público interfaz CustomClientDetailsRepository extiende CouchbasePagingAndSortingRepository<CustomClientDetails, Cadena> { CustomClientDetails findByClientId(Cadena clientId); } |
Ahora, podemos implementar el ServicioDeDetallesDelCliente de la clase de seguridad de 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 |
importar org.springframework.judías.fábrica.anotación.Autowired; importar org.springframework.seguridad.oauth2.proveedor.DetallesDelCliente; importar org.springframework.seguridad.oauth2.proveedor.ServicioDeDetallesDelCliente; importar org.springframework.seguridad.oauth2.proveedor.ClientRegistrationException; importar org.springframework.seguridad.oauth2.proveedor.cliente.BaseClientDetails; importar org.springframework.estereotipo.Servicio; importar java.util.flujo.Coleccionistas; @Servicio público clase CouchbaseClientDetailsService implementa ServicioDeDetallesDelCliente { @Autowired privado CustomClientDetailsRepository customClientDetailsRepository; @Anular público DetallesDelCliente loadClientByClientId(Cadena clientId) lanza ClientRegistrationException { CustomClientDetails cliente = customClientDetailsRepository.findByClientId(clientId); Cadena resourceIds = cliente.getResourceIds().flujo().recoja(Coleccionistas.unirse a(",")); Cadena ámbitos = cliente.getScope().flujo().recoja(Coleccionistas.unirse a(",")); Cadena grantTypes = cliente.getAuthorizedGrantTypes().flujo().recoja(Coleccionistas.unirse a(",")); Cadena autoridades = cliente.getAuthorities().flujo().recoja(Coleccionistas.unirse a(",")); BaseClientDetails base = nuevo BaseClientDetails(cliente.getClientId(), resourceIds, ámbitos, grantTypes, autoridades); base.setClientSecret(cliente.getClientSecret()); base.setAccessTokenValiditySeconds(cliente.getAccessTokenValiditySeconds()); base.setRefreshTokenValiditySeconds(cliente.getRefreshTokenValiditySeconds()); base.setAdditionalInformation(cliente.getAdditionalInformation()); base.setAutoApproveScopes(cliente.getScope()); devolver base; } } |
Tenga en cuenta que estoy utilizando el BaseClientDetails en lugar de implementar la clase DetallesDelCliente interfaz. Parece ser la mejor opción, ya que incluso la implementación estándar de JDBC la utiliza.
Por último, tenemos que cambiar nuestro AuthorizationServerConfig utilizar nuestro CouchbaseClientDetailsService:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Configuración @ActivarServidorAutorización público clase AuthorizationServerConfig extiende AuthorizationServerConfigurerAdapter { @Autowired privado CouchbaseClientDetailsService couchbaseClientDetailsService; @Override público void configure(ConfiguradorDeDetallesDelCliente configurador) lanza Excepción { configurador.conDetallesDelCliente(couchbaseClientDetailsService); } } |
Este es el aspecto de toda la clase:
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 |
importar org.springframework.judías.fábrica.anotación.Autowired; importar org.springframework.contexto.anotación.Configuración; importar org.springframework.seguridad.autenticación.AuthenticationManager; importar org.springframework.seguridad.cripto.contraseña.Codificador de contraseñas; importar org.springframework.seguridad.oauth2.config.anotación.configuradores.ConfiguradorDeDetallesDelCliente; importar org.springframework.seguridad.oauth2.config.anotación.web.configuración.AuthorizationServerConfigurerAdapter; importar org.springframework.seguridad.oauth2.config.anotación.web.configuración.EnableAuthorizationServer; importar org.springframework.seguridad.oauth2.config.anotación.web.configuradores.AuthorizationServerEndpointsConfigurer; importar org.springframework.seguridad.oauth2.config.anotación.web.configuradores.AuthorizationServerSecurityConfigurer; importar org.springframework.seguridad.oauth2.proveedor.ficha.TokenStore; @Configuración @ActivarServidorAutorización público clase AuthorizationServerConfig extiende AuthorizationServerConfigurerAdapter { @Autowired privado TokenStore almacén de fichas; @Autowired privado AuthenticationManager authenticationManager; @Autowired privado CouchbaseClientDetailsService couchbaseClientDetailsService; @Autowired privado Codificador de contraseñas codificador de contraseñas; @Override público void configure(ConfiguradorDeDetallesDelCliente configurador) lanza Excepción { configurador.conDetallesDelCliente(couchbaseClientDetailsService); } @Override público void configure(AuthorizationServerEndpointsConfigurer puntos finales) lanza Excepción { puntos finales.almacén de fichas(almacén de fichas) .authenticationManager(authenticationManager); } @Override público void configure( AuthorizationServerSecurityConfigurer oauthServer) lanza Excepción { oauthServer .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } } |
Ahora puede simplemente insertar un nuevo cliente en su base de datos y utilizar estas credenciales para autenticarse a través de 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 Cadena GRANT_TYPE_PASSWORD = "contraseña"; estático final Cadena CÓDIGO_AUTORIZACIÓN = "authorization_code"; estático final Cadena REFRESH_TOKEN = "refresh_token"; estático final Cadena IMPLÍCITO = "implícito"; estático final Cadena ALCANCE_LEER = "leer"; estático final Cadena SCOPE_WRITE = "escribir"; estático final Cadena CONFÍE EN = "confianza"; privado void createOauthClients() { CustomClientDetails cliente = nuevo CustomClientDetails(); cliente.setId("someId"); cliente.setResourceIds(nuevo HashSet<>(Matrices.asList("resource_id")) ); cliente.setClientId("android-cliente"); cliente.setClientSecret("android-secret"); cliente.setAuthorizedGrantTypes(nuevo HashSet<>(Matrices.asList(GRANT_TYPE_PASSWORD, CÓDIGO_AUTORIZACIÓN, REFRESH_TOKEN, IMPLÍCITO))); cliente.setScope(nuevo HashSet<>(Matrices.asList(ALCANCE_LEER, SCOPE_WRITE, CONFÍE EN))); cliente.setSecretRequired(verdadero); cliente.setAccessTokenValiditySeconds(50000); cliente.setRefreshTokenValiditySeconds(50000); cliente.setScoped(falso); customClientDetailsRepository.guardar(cliente); } |
TL;DR - El truco está en aplicar el org.springframework.security.oauth2.provider.ClientDetailsService y pasarlo como parámetro a su ConfiguradorDeDetallesDelCliente:
1 2 3 4 |
@Override público void configure(ConfiguradorDeDetallesDelCliente configurador) lanza Excepción { configurador.conDetallesDelCliente(couchbaseClientDetailsService); } |
Si tienes alguna pregunta, envíame un tweet a @deniswsrosa