当前位置: 首页 > news >正文

OAuth 2.0 安全授权

一、什么是 OAuth 2.0?

OAuth 2.0 是一个授权框架,它允许第三方应用程序在获得用户授权后,代表用户访问该用户在另一个服务提供商上存储的资源,而无需分享用户的密码。

  • 重要区别:OAuth 2.0 是关于授权,而非认证。
    • 认证:是确认“你是谁”的过程。(例如:用账号密码登录)
    • 授权:是确认“你被允许做什么”的过程。(例如:授权一个App来管理你的QQ邮箱)

二、为什么需要 OAuth 2.0?

在没有 OAuth 的时代,如果你想用一个第三方应用(比如一个在线邮件管理工具)来管理你的多个邮箱,你不得不把邮箱的账号密码交给这个第三方应用。这会带来巨大的风险:

  1. 密码泄露:第三方应用可能不安全,或者会滥用你的密码。
  2. 权限过大:应用不仅获得了读取邮件的权限,还可能获得删除邮件、发送邮件等所有权限。
  3. 难以撤销:一旦密码给出,除非修改密码,否则无法单独撤销该应用的访问权。

OAuth 2.0 通过引入一个访问令牌 完美地解决了这些问题。

三、OAuth 2.0 的核心角色

在一个 OAuth 2.0 流程中,通常涉及四个角色:

  1. 资源所有者: 拥有受保护资源的用户(就是你)。
  2. 客户端: 想要访问用户资源的第三方应用程序(例如,一个想访问你微信好友列表的社交App)。
  3. 授权服务器: 服务提供商用来处理认证和授权的服务器。它负责在用户授权后,向客户端颁发访问令牌。
  4. 资源服务器: 存放用户受保护资源的API服务器。客户端使用访问令牌来访问资源服务器。

四、OAuth2.0 四种模式

基于不同的使用场景,OAuth2.0设计了四种模式来获取访问令牌。Spring Security OAuth2提供了内置的端点,四种授权模式分别使用不同的端点和参数,我们在客户端配置中指定允许的授权类型,并在端点配置中设置必要的组件(如authenticationManager)来支持密码模式。

  • 授权端点(/oauth/authorize):用于处理授权请求。
  • 令牌端点(/oauth/token):用于颁发访问令牌。
  • 令牌验证端点(/oauth/check_token):用于验证令牌有效性。
  • 令牌吊销端点(/oauth/revoke_token):用于吊销令牌。
  • JWK端点( /oauth/token_key):获取JWT公钥。
4.1 授权码模式

这是最常用、最安全的模式,特别是用于有后端服务器的 Web 应用程序和移动应用程序。

  • 浏览器访问示例:

    • response_type=code
    http://localhost:8080/oauth/authorize?response_type=code&client_id=client1&redirect_uri=http://localhost:8081/callback&scope=all
    
  • 流程:

    • 第一步:用户访问授权端点
      • 客户端将用户重定向到/oauth/authorize,参数包括response_type=code、client_id、redirect_uri、scope等。
    • 第二步:用户认证并授权
      • 用户登录并授权,授权服务器重定向到redirect_uri并带上授权码。
    • 第三步:用授权码交换访问令牌
      • 客户端使用授权码向/oauth/token请求访问令牌,参数包括grant_type=authorization_code、code、redirect_uri等,并且需要客户端认证(通过HTTP Basic认证或参数传递client_id和client_secret)。
      • 换取访问令牌的请求:
        curl -X POST \http://localhost:8080/oauth/token \-H 'Authorization: Basic Y2xpZW50MToxMjM0NTY=' \  # client1:123456的Base64编码-H 'Content-Type: application/x-www-form-urlencoded' \-d 'grant_type=authorization_code&code=授权码&redirect_uri=http://localhost:8081/callback'
        
  • 特点:

    • 安全性高:关键的访问令牌不会通过浏览器暴露,只有授权码在前端传递,而授权码本身是短暂的且无法直接访问资源。
    • 支持刷新令牌:可以获取刷新令牌,用于在访问令牌过期后获取新的访问令牌,无需用户再次登录。
    • 适用场景:有后端的传统 Web 应用、移动 App(使用 PKCE 扩展增强安全)。
4.2 隐式模式

这是一种简化模式,访问令牌直接在浏览器的重定向 URI 的片段(#后面)中返回。该模式在现代 OAuth 2.1 标准中已被废弃,不推荐使用。

  • 浏览器访问示例:

    • response_type=token
    http://localhost:8080/oauth/authorize?response_type=token&client_id=client1&redirect_uri=http://localhost:8081/callback&scope=all
    
  • 流程

    • 第一步:用户访问授权端点
      • 客户端将用户重定向到/oauth/authorize,参数包括response_type=token、client_id、redirect_uri、scope等。
    • 第二步:用户认证并授权
      • 用户登录并授权,授权服务器重定向到redirect_uri并在URL的hash片段中直接返回访问令牌。
  • 特点:

    • 安全性低:访问令牌直接在浏览器地址栏中暴露,有被截获的风险。
    • 不支持刷新令牌:由于安全性考虑,不会返回刷新令牌。
    • 适用场景:过去用于纯前端 JavaScript 应用(单页应用 SPA),但现在已被授权码模式 + PKCE 完全取代。
4.3 密码模式

用户将其用户名和密码直接交给客户端应用,客户端应用再用这些信息向授权服务器申请令牌。

  • 浏览器访问示例:

    • grant_type=password
    curl -X POST \http://localhost:8080/oauth/token \-H 'Authorization: Basic Y2xpZW50MToxMjM0NTY=' \-H 'Content-Type: application/x-www-form-urlencoded' \-d 'grant_type=password&username=user&password=123456&scope=all'
    
  • 流程:

    • 用户直接访问令牌端点
      • 客户端直接向/oauth/token发送请求,参数包括grant_type=password、username、password、scope,并且需要客户端认证。
  • 特点:

    • 信任度要求极高:客户端应用会直接接触到用户的明文密码,这违背了 OAuth 的初衷(不暴露密码)。只在绝对信任的情况下使用,例如同一个公司内部的官方应用。
    • 安全性风险:如果客户端应用被入侵,用户密码将泄露。
    • 适用场景:第一方的高信任度应用,或者遗留系统迁移到 OAuth 的过渡方案。
4.4 客户端凭证模式

这种模式不涉及用户,是机器对机器的通信,用于客户端应用访问其自身拥有的资源,而不是代表某个用户。

  • 浏览器访问示例:

    • grant_type=client_credentials
    curl -X POST \http://localhost:8080/oauth/token \-H 'Authorization: Basic Y2xpZW50MToxMjM0NTY=' \-H 'Content-Type: application/x-www-form-urlencoded' \-d 'grant_type=client_credentials&scope=all'
    
  • 流程:

    • 用户直接访问令牌端点
      • 客户端向/oauth/token发送请求,参数包括grant_type=client_credentials、scope,并且需要客户端认证。
  • 特点:

    • 无用户参与:整个流程没有用户授权环节。
    • 访问自有资源:获取的令牌用于访问该客户端自己控制的资源(例如,一个后台服务调用另一个 API 来获取系统级别的数据)。
    • 适用场景:微服务之间的 API 调用、后台作业、服务器与服务器之间的通信。

五、搭建 OAuth2-Server

这里使用Spring Boot 2.x 和 Spring Security OAuth2 来搭建一个 OAuth2 Server 认证中心。主要步骤:

  1. 创建Spring Boot项目,添加依赖。
  2. 配置授权服务器。
  3. 配置资源服务器(如果需要保护资源)。
  4. 配置安全规则。
  5. 测试授权并访问保护资源。
步骤1:创建Spring Boot项目

使用Spring Initializr 创建一个项目,并在pom.xml中添加依赖:

<dependencies><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.1.0.RELEASE</version></dependency>
</dependencies>
步骤2:配置授权服务器

创建一个授权服务器配置类,使用@EnableAuthorizationServer注解。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
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 AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.tokenKeyAccess("permitAll()")   // 公开/oauth/token_key端点.checkTokenAccess("isAuthenticated()") // 认证后可访问/oauth/check_token端点.allowFormAuthenticationForClients(); // 允许客户端使用表单认证}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("client1") // 客户端ID.secret(passwordEncoder.encode("123456")) // 客户端密钥.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit") // 授权模式.scopes("all") // 授权范围.redirectUris("http://localhost:8080/callback") // 重定向URI,用于授权码模式和简化模式.autoApprove(true) // 自动批准,跳过授权确认页面.and().withClient("client2").secret(passwordEncoder.encode("123456")).authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit").scopes("all").redirectUris("http://localhost:8080/callback").autoApprove(true);}
}
步骤3:配置资源服务器

创建一个资源服务器配置类,使用@EnableResourceServer注解。

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 {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll() // 公开访问.anyRequest().authenticated(); // 其他请求需要认证}
}
步骤4:配置安全规则

我们需要配置一个密码编码器,并设置基本的安全规则。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.crypto.password.PasswordEncoder;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("123456")).roles("USER");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/oauth/**").permitAll() // OAuth2端点允许访问.anyRequest().authenticated().and().formLogin().permitAll();}
}
步骤5:测试授权并访问保护资源
  1. 创建一个测试控制器

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;@RestController
    public class TestController {@GetMapping("/public/hello")public String publicHello() {return "Hello Public";}@GetMapping("/private/hello")public String privateHello() {return "Hello Private";}
    }
    
  2. 获取访问令牌
    这里使用授权码模式来获取访问令牌:

    1. 在浏览器中访问:
      http://localhost:8080/oauth/authorize?response_type=code&client_id=client1&redirect_uri=http://localhost:8081/callback&scope=read
      
    2. 输入用户名和密码(user1/password1)进行登录。
    3. 授权服务器会重定向到http://localhost:8081/callback?code=授权码。
    4. 使用这个授权码,通过POST请求到/oauth/token获取访问令牌。
  3. 使用获取到的访问令牌访问受保护资源:

    curl -X GET \http://localhost:8080/private/hello \-H 'Authorization: Bearer <access_token>'
    
http://www.dtcms.com/a/550174.html

相关文章:

  • Rust 与数据库连接池的集成:安全与性能的深度耦合
  • 台州网站策划台州网站策划首页制作教程
  • 中国站长站甘肃省住房和建设厅官方网站
  • Golang学习笔记:后端性能优化秘籍(持续更新)
  • Easyx图形库应用(基础的AI开发原理)
  • arthas实现类的热部署
  • Rust 注释与文档注释:从代码可读性到 API 文档化的工程实践
  • 取名网站怎么做2022年新闻摘抄十条简短
  • 网站开发工具教程wordpress 关键词获取
  • tensorflow的广播机制
  • MIT-最大连续子序列和(MCS)
  • 深圳市住建局网站官网济南网站建设公司哪家好
  • Kubernetes资源管理全解析
  • 郑州企业型网站建设怎么做可以访问网站
  • 网站制作前必须做的事情有哪些网站行业
  • TC3xx芯片ACCEN寄存器保护详解
  • Linux上如何挂载磁盘
  • 卫星轨道计算中的数值精度陷阱:第三体引力摄动的稳定性优化
  • 白山网站seoe网站的图标怎么做
  • RHSCA---用户和组管理
  • 温州网站域名注册服务公司易语言如何做浏网站
  • 仿糗事百科网站源码dede二次开发分享+评论+互动国外网站域名
  • 仓颉语言中String的内存表示深度解析
  • NetSuite 中自定义基础打印模板的调整方法分享
  • 东城企业网站开发什么网站能免费做简历
  • “调用销毁者置于末尾”原则
  • GRPO相关优化论文
  • Openvins学习---ov_msckf中的State.h
  • 有什么网站可以做数学题项目建设全过程
  • 德庆网站建设良精企业网站管理系统