- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
在这篇文章中,我们将通过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上找到。
我有一个 webapp,它使用 php 服务器和数据库服务器执行大量 ajax 请求。我还创建了一个 iPhone 应用程序和一个 Android 应用程序,直到现在它们一直作为离线应用程序工作。 现
OAuth 的访问 token /刷新 token 流对我来说似乎非常不安全。帮助我更好地理解它。 假设我正在与利用 OAuth 的 API 集成(如 this one )。我有我的访问 token
这个问题在这里已经有了答案: 9年前关闭。 Possible Duplicate: How is oauth 2 different from oauth 1 我知道这两个不向后兼容。但是,既然已经实
我已经看到关于此的其他问题( here 、 here 和 here ),但我对任何解决方案都不满意,所以我再次询问。我正在启动一个 Web 应用程序,它将利用来自多个提供商(Google、Facebo
我知道(在 OAuth 中使用授权代码“授权代码”时),访问 token 的生命周期应该很短,但刷新 token 的生命周期可能很长。 所以我决定为我的项目: 访问 token 生命周期:1 天 刷新
在没有浏览器的情况下,我们可以在手机上的应用程序中使用 OAuth 吗? 如果没有浏览器,用户是否仍然可以批准 token 请求(以便消费者可以继续从服务提供者那里获取 protected 资源)?
用非常简单的术语来说,有人可以解释一下 OAuth 2 和 OAuth 1 之间的区别吗? OAuth 1 现在已经过时了吗?我们应该实现 OAuth 2 吗?我没有看到很多 OAuth 2 的实现;
修改表单例份验证登录过程并不难,因此除了正常的表单例份验证之外,WebClient 对象对由使用 Thinktecture IdentityModel 设置的 Web Api DAL 提供的 api/
我想连接到 LinkedIn 并通过他们的 API 提取一些信息。 LinkedIn API 使用 OAuth 2.0。 我读过的所有关于 OAuth 的文档(无论是在 LinkedIn 的上下文中还
OAuth 与其他身份验证标准的支持范围有多广? 这可能是社区维基的东西,但我还是要问。 我需要投资一些与服务器身份验证相关的东西,而且那里似乎有一些不错的东西。 最佳答案 OAuth 主要用作授权机
我有几个问题... 雅虎和微软 api 是否支持 oAuth 2.0? 如果是,那么主要是什么 应该采取的安全措施 转移时受到照顾 oAuth 1.0 到 oAuth 2.0。 Google API
我已经用谷歌 oAuth 开发了一个应用程序,这工作正常。 我可以登录并访问我的网站。 我的问题是,当我从我的应用程序中注销(注销)时,我删除了所有 session ,但未删除经过身份验证的 cook
我在 Internet 上寻找一些关于此的信息,最后在 RFC 上找到了 Oauth 1.0 协议(protocol):https://www.rfc-editor.org/rfc/rfc5849 您
我正在尝试制作 Google OpenID/OAuth hybrid签到工作。问题是它是一个可安装的网络(所以没有固定域),我也试图让它在我的开发机器上工作 - 所以返回 URL 类似于 http:/
我想构建一个独立与任何身份提供者(如 ADFS、OpenAM、oracle 身份)一起工作的应用程序。我的目的是验证来自任何一个 IDP 的登录用户,这些 IDP 配置为实现我的 SSO。 我不确定
我正在深入研究 Spring OAuth,发现一些相互矛盾的信息。 具体来说,this tutorial声明 /oauth/token 端点在将刷新 token 授予客户端应用程序之前处理用户名和密码
如何通过自定义命令行工具支持三足式 OAuth 工作流? 我想允许我的 CLI 工具的用户上网、登录并在本地缓存 token ,类似于 heroku login。正在做。 最佳答案 你必须扔掉同意屏幕
什么是 oauth 域?是否有任何免费的 oauth 服务?我可以将它用于 StackApps registration 吗? ?我在谷歌上搜索了很多,但找不到答案。 最佳答案 这是redirect_
我需要将我的 Delicious 书签下载到非 Web 应用程序,而无需持续的用户交互。我正在使用 Delicious 的 V2 API(使用 oAuth),但问题是他们的访问 token 似乎在一小
我正在尝试为两台服务器设置一个 nginx 负载均衡器/代理,并在两台服务器上运行 OAuth 身份验证的应用程序。 当 nginx 在端口 80 上运行时,一切都运行良好,但是当我将它放在任何其他端
我是一名优秀的程序员,十分优秀!