在这篇文章中,我们将通过Spring Boot配置和启用Oauth2。我们将用Oauth2来保护我们的REST API,建立一个授权服务器来验证我们的客户端,并为未来的通信提供一个access_token。
在我们深入了解细节之前,让我们快速回顾一下Oauth2。Oauth2是一个授权框架,使应用程序能够在HTTP服务上获得对用户账户的有限访问。它的工作方式是将用户认证委托给托管用户账户的服务,并授权第三方应用程序访问用户账户。Oauth2为网络和桌面应用以及移动设备提供授权流程。
Oauth定义了四个主要角色。
资源所有者:用户 - 资源所有者是授权应用访问其账户的用户。
资源/授权服务器 - 资源服务器托管受保护的用户账户,授权服务器验证用户的身份,然后向应用发放访问令牌。
客户端。应用程序 - 客户端是想要访问用户账户的*应用程序。在它这样做之前,用户必须允许它,而且API必须验证授权。
让我们看看这个Oauth2工作流程是怎样的。
在进行OAuth2工作时,请确保你对访问令牌和刷新令牌有一个清晰的认识
让我们来设置一个授权服务器,以启用Spring Boot的Oauth2。我们可以选择使用IDE(如IntelliJ IDEA)创建应用程序,也可以使用Spring Boot CLI创建一个应用程序。
$ spring init --dependencies=web,actuator my-project
如果你喜欢一个更直观的界面来生成初始结构,我们可以使用Spring Initializer。
点击 "生成 "按钮,在你的本地机器上下载项目。我们为我们的应用程序选择了以下依赖项。
为了启用Oauth支持,在pom.xml文件中添加以下依赖。
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>
这个依赖将为我们的应用程序添加使用Oauth2功能的所有先决条件。下一步是为我们的应用程序添加一些配置。在src/main/resources/application.properties
文件中添加以下条目。
user.oauth.clientId=javadevjournal
user.oauth.clientSecret=1234$#@!
user.oauth.redirectUris=http://localhost:8081/login
user.oauth.user.username=javadevjournal
user.oauth.user.password=javadevjournal
user.oauth.accessTokenValidity=300
user.oauth.refreshTokenValidity=240000
根据你的要求改变这些值。
上述配置设置了授权服务器在设置过程中使用的值(你可以随时使用数据库来存储这些值)。为了激活授权服务器,添加add @EnableResourceServer
注释。
@SpringBootApplication
@EnableResourceServer
public class SpringBootAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAuthServerApplication.class, args);
}
}
我们的下一步是配置我们的资源服务器。让我们创建OAuth2AuthServerConfiguration
并扩展AuthorizationServerConfigurerAdapter
.这个Spring配置类启用并配置了一个OAuth授权服务器。
package com.javadevjournal.oauth2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Value("${user.oauth.clientId}")
private String clientID;
@Value("${user.oauth.clientSecret}")
private String clientSecret;
@Value("${user.oauth.redirectUris}")
private String redirectURLs;
@Value("${user.oauth.accessTokenValidity}")
private int accessTokenValidity;
@Value("${user.oauth.refreshTokenValidity}")
private int refreshTokenValidity;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(clientID)
.secret(passwordEncoder.encode(clientSecret))
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.scopes("user_info")
.authorities("READ_ONLY_CLIENT")
.redirectUris(redirectURLs)
.accessTokenValiditySeconds(accessTokenValidity)
.refreshTokenValiditySeconds(refreshTokenValidity);
}
}
这个类将在客户端应用程序得到认证后返回令牌。让我们检查一下一些重要的内容。
denyAll()
方法后面保护这些端点。tokenKeyAccess
和tokenKeyAccess
启用这些端点。ClientDetailsServiceConfigurer
用于定义*客户端细节服务的内存或JDBC实现。*我们在这篇文章中使用内存方法,但我建议为你的生产环境使用JDBC支持的方法。配置是使用以下属性。客户端 - 在认证服务器上注册的客户端ID。我们使用application.properties文件来定义它。
Secret - 客户端秘密(查看application.properties文件)。
Scope - 客户端应用程序的范围。这显示了我们给客户端应用程序的访问权限。如果范围未定义或为空(默认),则客户端不受范围限制。
authorizedGrantTypes - 授予客户端使用的类型。默认值为空。
authorities - 授予客户端的权限(常规的Spring Security权限)。
广告
广告
redirectUris - 将用户代理重定向到客户端的重定向端点。它必须是一个绝对的URL。
Token Validity - 最后两个配置设置访问和刷新令牌的有效性。
让我们为我们的资源服务器添加一些额外的配置。创建一个类OAuth2ResourceServerConfig
并扩展ResourceServerConfigurerAdapter
类。
@Configuration
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/").permitAll();
}
}
以上配置使所有端点的保护开始于/api
。所有其他端点都不安全,没有OAuth安全就可以访问。
Spring security Oauth2还提供了一种机制来认证用户本身。这是一个基于表单的安全功能。创建一个SecurityConfiguration
类,它扩展了SecurityConfiguration
类。
package com.javadevjournal.oauth2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@Order(1)
public class OauthSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${user.oauth.user.username}")
private String username;
@Value("${user.oauth.user.password}")
private String password;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/oauth/authorize**", "/login**", "/error**")
.permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(username).password(passwordEncoder().encode(password)).roles("USER");
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
上述类对我们的授权服务器进行认证请求。这就完成了我们授权服务器的核心设置。让我们创建一个受保护的资源来测试整个工作流程。
为了测试我们的应用程序,让我们创建一个REST控制器。我们的控制器将根据用户ID来返回用户的详细信息。这个资源是安全的,没有有效的Oauth令牌将无法访问。如果我们在请求中没有传递有效的令牌,系统将不允许访问并向客户端抛出未经授权的异常。
package com.javadevjournal.controller;
import com.javadevjournal.data.CustomerData;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
@GetMapping("/customer/{userId}")
public CustomerData getCustomerProfile(@PathVariable("userId") String userId) {
return getCustomer(userId);
}
private CustomerData getCustomer(final String userId) {
CustomerData customer = new CustomerData();
customer.setEmail("[email protected]");
customer.setFirstName("Demo");
customer.setLastName("User");
customer.setAge(21);
customer.setId(userId);
return customer;
}
}
客户数据
package com.javadevjournal.data;
public class CustomerData {
private String firstName;
private String lastName;
private int age;
private String email;
private String id;
public CustomerData() {}
public CustomerData(String firstName, String lastName, int age, String email, String id) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.email = email;
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
在测试的第一部分,我将使用Postman。当任何第三方试图访问客户资料数据时,该服务需要oauth2令牌。
这个过程的第一步是从资源所有者那里获得授权许可。要获得授权许可,请使用下面的URL(在现实世界的应用中,客户将被重定向到这个网站,并将被提示给予API访问某种资源的许可)。
http://localhost:8080/oauth/authorize?client_id=javadevjournal&response_type=code&scope=user_info<code>
这个URL带来一个登录页面。一旦客户提供了登录信息,系统就会重定向到授权访问页面。该页面为客户提供了一个选项,以批准/拒绝该请求或为第三方应用程序提供某些访问权限。(你还记得当你在你的Facebook上添加任何应用程序时,它将你重定向到一个页面来提供你的权限吗?)
提供用户名和密码(关于这些配置,请参考第2节)。
一旦我们批准请求,它将重定向到一个URL(检查user.oauth.redirectUris属性)。这个重定向的URL也将包含一个代码作为查询字符串的一部分(http://localhost:8081/login?code=13428u
)。这个代码是第三方应用程序的授权代码。
一旦我们有了授权,下一步就是要获得访问令牌。为了得到访问令牌,我们需要传递在上一步中收到的代码。对于这个演示,发送一个简单的cURL请求。
curl -X POST \
http://localhost:8080/oauth/token \
-H 'authorization: Basic amF2YWRldmpvdXJuYWw6MTIzNCQjQCE=' \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-H 'postman-token: f24e14c3-a90a-4866-59ae-3691dfb3ea0a' \
-d 'code=ntCgjD&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2Flogin&scope=user_info'
在一个成功的请求中,认证服务器将在响应中返回访问令牌
{
"access_token": "791dccdf-c41f-42c1-9b88-93853ed5c87b",
"token_type": "bearer",
"refresh_token": "ec2ef96e-1792-4188-b397-87b1a2afdeb4",
"expires_in": 122,
"scope": "user_info"
}
一旦我们得到访问令牌,让我们通过在请求中传递访问令牌来获得用户信息。
下面是cURL请求
curl -X GET \
http://localhost:8080/api/customers/customer/1 \
-H 'Authorization: Bearer f4e93f7c-59c3-4ca3-a5c3-0e74582b1b18' \
-H 'cache-control: no-cache'
[pullquote align="normal"] 在这篇文章中,为了保持简单,我省略了一些信息,比如将令牌存储在数据库中,或者注入一个用户服务,不使用内存中的用户。这些都可以使用Spring安全系统轻松配置 [/pullquote] 。
以下是完整的pom.xml
文件供你参考。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.javadevjournal</groupId>
<artifactId>spring-boot-auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-auth-server</name>
<description>Spring Boot Authorization Server</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在这篇文章中,我们讨论了如何用Spring Boot配置和启用Oauth2。我们研究了使用Spring Boot和Spring Security的步骤,以便为我们基于REST的应用程序启用Oauth2支持。这篇文章的源代码可以在GitHub上找到。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.javadevjournal.com/spring-boot/spring-boot-oauth2/
内容来源于网络,如有侵权,请联系作者删除!