Spring Boot实战:SSO和OAuth2.0
SSO和OAuth2.0
SSO(单点登录)和OAuth 2.0 是两个在认证和授权场景中常用的技术概念。它们的应用场景、目标和工作机制不同,但在一些方面也有联系。以下是它们的区别和联系的详细分析。
一、SSO(Single Sign-On)
1.1 定义
SSO(单点登录)是一种认证机制,它允许用户只需登录一次即可访问多个独立的应用系统,而不需要在每个系统上重复登录。SSO的核心是用户身份认证,即确定用户是谁,并在多个应用系统之间共享这一登录状态。
1.2 工作机制
SSO通常的工作流程如下:
- 用户访问一个需要认证的系统。
- 如果用户未登录,系统将用户重定向到SSO认证中心。
- 用户在认证中心登录,认证通过后,SSO认证中心生成一个令牌并返回给系统。
- 系统验证该令牌,用户成功登录并获得访问权限。
- 当用户访问其他系统时,系统使用同样的令牌或共享会话信息进行认证,允许用户无缝访问。
1.3 应用场景
- 企业内部多个系统的统一登录。
- 门户网站中多个子系统共享同一登录入口。
- 需要在不同应用之间频繁切换的场景。
1.4 核心目标
- 用户身份认证:主要目标是解决用户的单点登录问题,即多个系统共享用户的登录状态。
二、OAuth 2.0
2.1 定义
OAuth 2.0 是一种授权协议,允许第三方应用在不暴露用户凭据的情况下,安全地访问用户的资源。OAuth 2.0 的核心是授权,即用户授权第三方应用访问其资源的权限,而不是直接进行用户认证。
2.2 工作机制
OAuth 2.0的典型授权流程如下:
- 客户端(第三方应用)请求用户授权。
- 用户被引导到授权服务器,在登录并同意授权后,授权服务器会返回一个授权码给客户端。
- 客户端使用授权码向授权服务器请求访问令牌。
- 授权服务器颁发
access_token
,客户端使用该令牌访问资源服务器上的受保护资源。
2.3 应用场景
- 第三方应用希望访问用户的数据或服务(如社交媒体API、支付系统)。
- 用户授权应用访问其云存储文件、社交平台上的照片等场景。
- 应用间的API授权和集成。
2.4 核心目标
- 授权:主要解决第三方应用访问用户资源的问题,让用户能够控制第三方应用访问的权限和范围。
三、SSO与OAuth 2.0的区别
特性 | SSO(单点登录) | OAuth 2.0(授权) |
---|---|---|
核心概念 | 用户身份认证,解决多系统共享登录状态 | 授权,允许第三方应用代表用户访问资源 |
重点 | 认证,确定用户身份 | 授权,控制第三方应用对资源的访问 |
典型场景 | 用户在多个应用之间切换时无需重复登录 | 第三方应用请求访问用户资源(API、数据) |
主要角色 | 用户、SSO认证中心、多个应用系统 | 资源拥有者、客户端(应用)、授权服务器、资源服务器 |
令牌使用方式 | 会话、Cookie 或 SSO令牌用于标识用户身份 | 通过access_token 或 refresh_token 授权访问资源 |
授权范围 | 不涉及资源授权,主要是身份认证 | 用户可以细化对第三方应用的授权范围 |
安全目标 | 提供用户统一的登录体验,减少多次登录风险 | 控制第三方应用对用户数据的访问权限 |
实现复杂度 | 相对简单,主要关注登录状态共享 | 较高,涉及授权、令牌管理、授权范围和安全性 |
四、SSO与OAuth 2.0的联系
尽管SSO和OAuth 2.0在概念上有所不同,但它们在某些情况下可以结合使用,尤其是在现代的分布式系统和开放平台中。
4.1 SSO和OAuth 2.0的结合使用
- OAuth 2.0 作为 SSO 的实现手段:OAuth 2.0通过授权服务器认证用户,并生成授权码或访问令牌(access token),允许用户使用相同的令牌在多个系统间访问资源,实现类似SSO的效果。例如,用户在一个门户网站(SSO认证中心)登录后,可以使用OAuth 2.0生成的令牌访问其他子系统,而不需要每次都重新登录。
- OpenID Connect (OIDC):OIDC是基于OAuth 2.0的认证层协议,结合了OAuth 2.0的授权和SSO的认证功能。OIDC在OAuth 2.0的基础上,添加了用户身份信息,允许用户通过OAuth 2.0协议认证并共享登录状态。因此,OpenID Connect可以被视为一种结合了SSO和OAuth 2.0的协议,是一种标准的SSO解决方案。
4.2 SSO与OAuth 2.0的配合场景
- 门户系统:在一些复杂的系统中,用户可以通过SSO实现单点登录进入门户网站,之后门户网站使用OAuth 2.0的授权机制授予用户对不同子系统的访问权限。
- 微服务架构:在微服务架构中,可以结合SSO和OAuth 2.0。用户通过SSO登录系统后,系统使用OAuth 2.0生成访问令牌,用户携带该令牌在不同的微服务间访问受保护的资源。每个微服务可以验证令牌的有效性,从而保证访问的安全性和便捷性。
- 跨组织系统:在跨组织系统中,用户可以通过SSO登录主系统,然后通过OAuth 2.0授权机制访问其他组织的系统或资源。例如,一个企业用户可以在企业门户上登录(SSO),然后通过OAuth 2.0授权机制访问其他合作伙伴的API资源。
五、总结
- SSO主要解决用户认证问题,让用户在多个系统之间可以使用单一的登录状态,实现“登录一次,访问多处”的效果。
- OAuth 2.0主要解决授权问题,让第三方应用在不获取用户凭据的情况下,可以安全地访问用户的资源。
- SSO和OAuth 2.0在某些场景下可以结合使用。OAuth 2.0可以充当SSO的实现方式,通过授权服务器生成的令牌可以实现单点登录效果,而OpenID Connect(基于OAuth 2.0的认证协议)就是一个将SSO和OAuth 2.0结合的标准。
- 在实际应用中,OAuth 2.0适合用于API访问、授权控制,而SSO适合用于统一的用户登录体验。结合SSO和OAuth 2.0可以构建一个完整的认证和授权解决方案,尤其适合分布式系统和微服务架构。
Spring Boot实现SSO
在Spring Boot项目中实现单点登录(SSO)功能,允许第三方系统通过SSO登录你的系统,可以通过OAuth 2.0协议和JWT(JSON Web Token)来实现。SSO的目标是让用户只需在SSO认证中心登录一次,即可访问多个系统而无需重复登录。下面将详细介绍如何实现这种方案。
一、SSO(单点登录)的基本原理
SSO的工作原理是多个系统共享用户的登录状态,通过集中式认证和授权服务器来统一管理登录。具体流程如下:
- 用户访问第三方系统:用户访问第三方系统A,但未登录。
- 重定向到SSO认证中心:第三方系统将用户重定向到SSO认证中心(授权服务器)。
- 用户登录并认证:用户在SSO认证中心登录并完成认证。
- 生成令牌并返回:SSO认证中心生成授权码或访问令牌,返回给第三方系统。
- 第三方系统验证令牌:第三方系统使用该令牌访问你的系统或资源服务器,以验证用户身份。
- 跨系统共享认证状态:当用户再次访问其他系统(如系统B),无需再次登录。
二、技术选型
在Spring Boot中,可以使用以下技术来实现SSO:
- Spring Security OAuth2:提供OAuth 2.0的授权和认证支持。
- JWT:使用JWT作为令牌,保存用户的认证信息,使系统能够基于令牌验证用户的身份。
- Spring Security:用于管理用户的认证和授权。
三、实现步骤
3.1 添加依赖
首先,在pom.xml
中添加Spring Security、OAuth2和JWT的依赖。
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth2 依赖 -->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<!-- JWT 支持 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
3.2 配置授权服务器(Authorization Server)
授权服务器是整个SSO的核心,它负责用户的认证和生成访问令牌。在Spring Boot中可以通过配置OAuth 2.0来实现。
1. 创建AuthorizationServerConfig
类
在Spring Boot项目中,创建一个AuthorizationServerConfig
类来配置授权服务器。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("third-party-client-id")
.secret("{noop}third-party-client-secret")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.redirectUris("http://localhost:8081/callback"); // 回调地址
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(new JwtTokenStore(accessTokenConverter()))
.accessTokenConverter(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("mySecretKey"); // 设置JWT的签名密钥
return converter;
}
}
此配置实现了OAuth 2.0的授权模式,并且通过JWT生成访问令牌,第三方系统可以使用授权码获取令牌,并使用它来访问受保护的资源。
3.3 配置资源服务器(Resource Server)
资源服务器托管你的受保护资源,并通过验证令牌的合法性来控制资源的访问。
1. 创建ResourceServerConfig
类
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // 公共资源
.antMatchers("/private/**").authenticated(); // 受保护资源
}
}
2. 创建受保护资源的控制器
定义一个受保护资源的控制器,用于测试SSO的访问控制。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResourceController {
@GetMapping("/private/data")
public String getPrivateData() {
return "This is a protected resource!";
}
@GetMapping("/public/data")
public String getPublicData() {
return "This is a public resource!";
}
}
3.4 配置第三方系统(客户端应用)
第三方系统作为客户端应用,需要向授权服务器请求授权,并使用获取到的令牌访问受保护资源。
1. 在application.yml
中配置OAuth 2.0客户端信息
spring:
security:
oauth2:
client:
registration:
sso-client:
client-id: third-party-client-id
client-secret: third-party-client-secret
scope: read,write
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
authserver:
authorization-uri: http://localhost:8080/oauth/authorize
token-uri: http://localhost:8080/oauth/token
user-info-uri: http://localhost:8080/userinfo
2. 使用Spring Security OAuth2登录
在SecurityConfig
类中启用OAuth2登录。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login(); // 启用OAuth2登录
}
}
四、SSO工作流程
-
第三方系统请求授权码:用户访问第三方系统的受保护资源,系统检测到用户未登录,将用户重定向到SSO认证中心(授权服务器)。
-
SSO认证中心处理认证请求:用户在SSO认证中心登录并通过认证后,授权服务器生成授权码并重定向回第三方系统的回调地址。
-
第三方系统获取访问令牌:第三方系统使用授权码向授权服务器请求访问令牌,授权服务器返回访问令牌给第三方系统。
-
访问受保护资源:第三方系统携带访问令牌访问资源服务器,资源服务器验证令牌的合法性后返回受保护资源。
-
其他系统共享登录状态:如果用户再次访问其他系统,这些系统可以使用同样的认证流程共享用户的登录状态,无需用户再次登录。
五、常见问题及建议
- 令牌的安全性:在生产环境中,建议使用HTTPS加密传输,防止令牌被拦截,JWT签名密钥也应妥善保管。
- 令牌的过期与刷新:访问令牌通常设置较短的有效期,可以使用刷新令牌机制延长会话,避免用户频繁登录。
- SSO登出与会话管理:在SSO环境下,登出操作需要清除各个系统的会话信息,可以通过分布式Session或集中式会话管理。
- 日志和监控:对登录、授权和资源访问等操作进行日志记录,方便后期审计和问题排查。
六、总结
通过以上配置,可以在Spring Boot项目中实现一个OAuth 2.0 SSO的认证授权系统,让第三方系统通过SSO登录你的系统。授权服务器集中管理用户认证,生成和验证JWT令牌,资源服务器通过验证令牌控制资源访问,客户端应用通过OAuth2流程安全地访问受保护资源。这种实现方式不仅提供了SSO功能,还具备了灵活的授权控制,非常适合在分布式架构中使用。
Spring Boot实现OAuth2.0授权
在Spring Boot中实现OAuth 2.0授权,允许第三方系统访问你的系统资源,通常包括搭建授权服务器、资源服务器,并通过OAuth 2.0协议来进行认证和授权。这种实现能够确保第三方系统安全地访问受保护的资源,而无需直接提供用户的凭据。
以下是实现OAuth 2.0授权的详细步骤,用于让第三方系统访问你的系统。
一、OAuth 2.0授权的基本工作原理
OAuth 2.0的授权流程主要包含以下几个步骤:
- 授权请求:第三方系统通过OAuth 2.0协议向授权服务器发起授权请求。用户被重定向到授权服务器,并在此进行登录。
- 用户同意授权:用户登录并同意授权后,授权服务器生成授权码并返回给第三方系统。
- 获取访问令牌:第三方系统使用授权码向授权服务器请求访问令牌(
access_token
)。 - 访问受保护资源:第三方系统使用
access_token
访问资源服务器上的受保护资源。
二、项目结构
OAuth 2.0授权在Spring Boot项目中通常需要三个主要组件:
- 授权服务器(Authorization Server):负责处理用户认证和授权请求,并生成访问令牌。
- 资源服务器(Resource Server):托管受保护资源,验证令牌的合法性。
- 客户端应用(Client Application):第三方系统,通过OAuth 2.0协议获取访问令牌并使用它来访问资源。
三、实现步骤
3.1 添加依赖
在Spring Boot项目的pom.xml
文件中,添加Spring Security和OAuth 2.0相关依赖:
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth2 Authorization Server 和 Resource Server 支持 -->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.4.0</version>
</dependency>
<!-- JWT 支持 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
3.2 配置授权服务器(Authorization Server)
授权服务器负责生成和管理令牌,并处理用户的授权流程。我们可以使用Spring Security OAuth 2.0来配置授权服务器。
1. 创建AuthorizationServerConfig类
在Spring Boot项目中创建一个AuthorizationServerConfig
类,继承AuthorizationServerConfigurerAdapter
,配置授权服务器。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id") // 第三方系统的客户端ID
.secret("{noop}client-secret") // 客户端密钥
.authorizedGrantTypes("authorization_code", "refresh_token") // 支持的授权模式
.scopes("read", "write") // 授权范围
.redirectUris("http://localhost:8081/callback"); // 回调地址
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 通过JWT生成令牌
endpoints.tokenStore(new JwtTokenStore(jwtAccessTokenConverter()))
.accessTokenConverter(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("mySecretKey"); // 设置签名密钥
return converter;
}
}
3.3 配置资源服务器(Resource Server)
资源服务器托管受保护资源,并验证令牌的有效性。资源服务器可以通过JWT验证令牌,确保只有持有有效access_token
的请求才能访问资源。
1. 创建ResourceServerConfig类
在Spring Boot项目中创建一个ResourceServerConfig
类,继承ResourceServerConfigurerAdapter
,配置资源服务器行为。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public").permitAll() // 公共接口
.antMatchers("/api/private").authenticated(); // 受保护资源
}
}
2. 受保护资源的控制器
在资源服务器中创建一个控制器,定义受保护的资源。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResourceController {
@GetMapping("/api/private")
public String getPrivateData() {
return "This is a protected resource!";
}
@GetMapping("/api/public")
public String getPublicData() {
return "This is a public resource!";
}
}
3.4 配置客户端应用(Client Application)
客户端应用(即第三方系统)需要通过OAuth 2.0协议获取访问令牌,并使用令牌访问受保护资源。
1. 配置客户端信息
在第三方系统的application.yml
中,配置OAuth 2.0客户端信息。
spring:
security:
oauth2:
client:
registration:
myclient:
client-id: client-id
client-secret: client-secret
scope: read,write
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
authserver:
authorization-uri: http://localhost:8080/oauth/authorize
token-uri: http://localhost:8080/oauth/token
user-info-uri: http://localhost:8080/userinfo
jwk-set-uri: http://localhost:8080/oauth/jwks
2. 使用Spring Security OAuth2登录
在客户端应用的SecurityConfig
类中启用OAuth2登录,并配置安全策略。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login(); // 启用OAuth2登录
}
}
3.5 授权流程演示
-
授权请求:第三方系统(客户端)发起授权请求,用户将被重定向到授权服务器进行登录和授权。典型的授权请求URL如下:
http://localhost:8080/oauth/authorize?response_type=code&client_id=client-id&redirect_uri=http://localhost:8081/callback
-
用户登录和授权:用户在授权服务器上登录,并同意授权第三方系统访问其资源。
-
获取授权码:授权服务器生成授权码,并通过重定向将其返回给第三方系统的回调地址。
-
获取访问令牌:第三方系统使用授权码向授权服务器请求访问令牌。
POST http://localhost:8080/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code code=AUTHORIZATION_CODE redirect_uri=http://localhost:8081/callback client_id=client-id client_secret=client-secret
-
访问受保护资源:第三方系统使用获得的
access_token
来访问资源服务器上的受保护资源。GET /api/private Authorization: Bearer access_token
资源服务器验证令牌的合法性后,返回受保护的数据。
四、常见问题及建议
- 令牌存储与安全性:在生产环境中,建议使用JWT作为令牌存储,并通过HTTPS加密通信,防止令牌泄露。
- 令牌过期管理:可以通过刷新令牌(
refresh_token
)机制来延长会话,避免用户频繁登录。 - 客户端凭证管理:客户端密钥(
client-secret
)需要妥善保护,不要泄露给未授权的用户或系统。 - 授权范围的控制:OAuth 2.0的授权范围可以控制第三方应用的访问权限,确保第三方只能访问必要的数据。
五、总结
通过以上步骤,可以在Spring Boot中实现OAuth 2.0授权机制,允许第三方系统在获得用户授权后,安全地访问受保护的资源。授权服务器负责用户的认证和令牌生成,资源服务器负责资源的保护,客户端应用使用令牌访问资源。通过这种方式,可以实现一个标准的OAuth 2.0授权流程,确保数据的安全和用户的访问控制。
原文地址:https://blog.csdn.net/print_helloword/article/details/143512519
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!