En este tutorial, aprenderemos a usar Spring OAuth2RestTemplate para realizar llamadas OAuth2 REST.
Crearemos una aplicación web de Spring capaz de enumerar los repositorios de una cuenta de GitHub.
Maven
Primero, debemos agregar las dependencias spring-boot-starter-security y spring-security-oauth2-autoconfigure a nuestro pom.xml. Como estamos construyendo una aplicación web, también necesitamos que se incluyan los artefactos spring-boot-starter-web y spring-boot-starter-thymeleaf.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Propiedades para oAuth2
A continuación, agreguemos la configuración de OAuth a nuestro archivo application.properties para poder conectar la cuenta de GitHub:
github.client.clientId=[CLIENT_ID]
github.client.clientSecret=[CLIENT_SECRET]
github.client.userAuthorizationUri=https://github.com/login/oauth/authorize
github.client.accessTokenUri=https://github.com/login/oauth/access_token
github.client.clientAuthenticationScheme=form
github.resource.userInfoUri=https://api.github.com/user
github.resource.repoUri=https://api.github.com/user/repos
Tenga en cuenta que debemos reemplazar [CLIENT_ID] y [CLIENT_SECRET] con valores de una aplicación GitHub OAuth. Podemos seguir la guía Crear una aplicación OAuth para registrar una nueva aplicación en GitHub:
Para crear una nueva aplicacion en github, hay que ir a este formulario:
Asegurémonos de que la URL de devolución de llamada de autorización esté configurada en http://localhost:8080, lo que redirigirá el flujo de OAuth a la página de inicio de nuestra aplicación web.
Configuración de OAuth2RestTemplate
Ahora es el momento de crear una configuración de seguridad para proporcionar a nuestra aplicación soporte OAuth2.
Primero, creemos la configuración de seguridad de Spring:
@Configuration
@EnableOAuth2Client
public class SecurityConfig {
OAuth2ClientContext oauth2ClientContext;
public SecurityConfig(OAuth2ClientContext oauth2ClientContext) {
this.oauth2ClientContext = oauth2ClientContext;
}
...
}
@EnableOAuth2Client nos da acceso a un contexto OAuth2 que usaremos para crear nuestra OAuth2RestTemplate.
Bean OAuth2RestTemplate
@Bean
public OAuth2RestTemplate restTemplate() {
return new OAuth2RestTemplate(githubClient(), oauth2ClientContext);
}
@Bean
@ConfigurationProperties("github.client")
public AuthorizationCodeResourceDetails githubClient() {
return new AuthorizationCodeResourceDetails();
}
Con esto, estamos usando las propiedades y el contexto de OAuth2 para crear una instancia de la plantilla.
La anotación @ConfigurationProperties inyecta todas las propiedades de github.client en la instancia de AuthorizationCodeResourceDetails.
Filtro de autenticación
Tercero, necesitamos un filtro de autenticación para manejar el flujo de OAuth2:
private Filter oauth2ClientFilter() {
OAuth2ClientAuthenticationProcessingFilter oauth2ClientFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/github");
OAuth2RestTemplate restTemplate = restTemplate();
oauth2ClientFilter.setRestTemplate(restTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(githubResource().getUserInfoUri(), githubClient().getClientId());
tokenServices.setRestTemplate(restTemplate);
oauth2ClientFilter.setTokenServices(tokenServices);
return oauth2ClientFilter;
}
@Bean
@ConfigurationProperties("github.resource")
public ResourceServerProperties githubResource() {
return new ResourceServerProperties();
}
Aquí le indicamos al filtro que inicie el flujo de OAuth2 en la URL /login/github de nuestra aplicación.
Configuración Spring Security
Finalmente, registremos OAuth2ClientContextFilter y creemos una configuración de seguridad web:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/login**", "/error**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.addFilterBefore(oauth2ClientFilter(), BasicAuthenticationFilter.class);
return http.build();
}
@Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(filter);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
return registration;
}
Protegemos las rutas de nuestras aplicaciones web y nos aseguramos de que OAuth2ClientAuthenticationProcessingFilter esté registrado antes que BasicAuthenticationFilter.
Uso del OAuth2RestTemplate
El objetivo principal de OAuth2RestTemplate es reducir el código necesario para realizar llamadas API basadas en OAuth2. Básicamente cubre dos necesidades de nuestra aplicación:
- Maneja el flujo de autenticación OAuth2
- Extiende Spring RestTemplate para hacer llamadas API
Ahora podemos usar OAuth2RestTemplate como un bean con conexión automática en un controlador web.
Vamos a crear el archivo index.html con las opciones de inicio de sesión y de inicio:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>OAuth2Client</title>
</head>
<body>
<h3>
<a href="/login/github" th:href="@{/home}" th:if="${#httpServletRequest?.remoteUser != undefined }">
Pagina principal
</a>
<a href="/hola" th:href="@{/login/github}" th:if="${#httpServletRequest?.remoteUser == undefined }">
GitHub Login
</a>
</h3>
</body>
</html>
A los usuarios no autenticados se les presentará la opción de inicio de sesión, mientras que los usuarios autenticados pueden acceder a la página de inicio.
Ahora, creemos un controlador para saludar al usuario autenticado de GitHub:
@Controller
public class AppController {
OAuth2RestTemplate restTemplate;
public AppController(OAuth2RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/home")
public String welcome(Model model, Principal principal) {
model.addAttribute("name", principal.getName());
return "home";
}
}
A los usuarios no autenticados se les presentará la opción de inicio de sesión, mientras que los usuarios autenticados pueden acceder a la página de inicio.
Ahora, creemos un controlador para saludar al usuario autenticado de GitHub:
@Controller
public class AppController {
OAuth2RestTemplate restTemplate;
public AppController(OAuth2RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/home")
public String welcome(Model model, Principal principal) {
model.addAttribute("name", principal.getName());
return "home";
}
}
Tenga en cuenta que tenemos un parámetro principal de seguridad en el método de bienvenida. Estamos usando el nombre del principal como un atributo del modelo de interfaz de usuario.
Echemos un vistazo a la plantilla home.html:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home</title>
</head>
<body>
<p>
Bienvenido <b th:inline="text"> [[${name}]] </b>
</p>
<h3>
<a href="/repos">Ver repositorios</a><br/><br/>
</h3>
<form th:action="@{/logout}" method="POST">
<input type="submit" value="Logout"/>
</form>
</body>
</html>
Además, estamos agregando un enlace para ver la lista de repositorios del usuario y una opción de cierre de sesión.
Ahora es el momento de usar OAuth2RestTemplate creado en el controlador anterior para presentar todos los repositorios de GitHub propiedad del usuario.
Primero, necesitamos crear la clase GithubRepo para representar un repositorio:
public class GithubRepo {
Long id;
String name;
// getters and setters
}
En segundo lugar, agreguemos una asignación de repositorios al AppController anterior:
@GetMapping("/repos")
public String repos(Model model) {
Collection<GithubRepo> repos = restTemplate.getForObject("https://api.github.com/user/repos", Collection.class);
model.addAttribute("repos", repos);
return "repositories";
}
OAuth2RestTemplate maneja todo el código repetitivo para realizar una solicitud a GitHub. Además, convierte la respuesta REST en una colección de GithubRepo.
Finalmente, creemos la plantilla repositories.html para iterar sobre la colección de repositorios:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Repositories</title>
</head>
<body>
<p>
<h2>Repos</h2>
</p>
<ul th:each="repo: ${repos}">
<li th:text="${repo.name}"></li>
</ul>
</body>
</html>
En este artículo, aprendimos a usar OAuth2RestTemplate para simplificar las llamadas REST a un servidor de recursos OAuth2 como GitHub.
Revisamos los componentes básicos de una aplicación web que ejecuta el flujo OAuth2. Luego, vimos cómo hacer una llamada a la API REST para recuperar todos los repositorios de un usuario de GitHub.