Rust的OAuth客户端:oauth2库
OAuth 2.0是委托访问的行业标准。它广泛用于通过第三方服务(Google、GitHub、Facebook)对用户进行授权,而无需传输密码。在Rust生态系统中,实现OAuth 2.0最流行且成熟的库之一是oauth2(crate oauth2)。它提供了一个安全、异步且灵活的API,用于与任何OAuth提供商协作。
主要功能
- 支持所有标准授权模式:授权码、客户端凭证、资源所有者密码凭证、隐式模式。
- 内置PKCE支持(Proof Key for Code Exchange),用于提高公共客户端的安全性。
- 异步操作,底层使用
reqwest或ureq。 - 类型安全:所有令牌、URL和参数都严格类型化,在编译阶段消除错误。
- 灵活配置,可通过配置端点和作用域适配任何提供商。
- 令牌管理:自动刷新(refresh)、检查过期时间。
安装
将依赖项添加到您的Cargo.toml中:
[dependencies]oauth2 = "4.4"tokio = { version = "1", features = ["full"] }serde = { version = "1", features = ["derive"] }reqwest = { version = "0.11", features = ["json"] }基本示例:通过Google授权
我们来看一个使用授权码+PKCE模式通过Google进行OAuth 2.0的完整流程:
use oauth2::{ AuthorizationCode, AuthUrl, ClientId, ClientSecret, CsrfToken, PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, TokenUrl,};use oauth2::basic::BasicClient;use oauth2::reqwest::async_http_client;use url::Url;
#[tokio::main]async fn main() -> Result<(), Box> { // 1. 使用Google的设置创建客户端 let client = BasicClient::new( ClientId::new("您的_GOOGLE_CLIENT_ID".to_string()), Some(ClientSecret::new("您的_GOOGLE_CLIENT_SECRET".to_string())), AuthUrl::new("https://accounts.google.com/o/oauth2/v2/auth".to_string())?, Some(TokenUrl::new("https://oauth2.googleapis.com/token".to_string())?), ) .set_redirect_uri(RedirectUrl::new("http://localhost:8080/callback".to_string())?);
// 2. 生成PKCE challenge let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
// 3. 构建用户授权URL let (auth_url, csrf_token) = client .authorize_url(CsrfToken::new_random) .add_scope(Scope::new("openid".to_string())) .add_scope(Scope::new("profile".to_string())) .add_scope(Scope::new("email".to_string())) .set_pkce_challenge(pkce_challenge) .url();
println!("请在浏览器中打开:{}", auth_url);
// 4. (模拟)从用户获取授权码 let code = "重定向后从浏览器获取的代码";
// 5. 用授权码交换令牌 let token_response = client .exchange_code(AuthorizationCode::new(code.to_string())) .set_pkce_verifier(pkce_verifier) .request_async(async_http_client) .await?;
println!("访问令牌:{}", token_response.access_token().secret()); println!("刷新令牌:{:?}", token_response.refresh_token());
Ok(())} 高级场景
1. 刷新令牌(Refresh Token)
当访问令牌过期时,使用刷新令牌获取新的令牌:
use oauth2::RefreshToken;
let refresh_token = RefreshToken::new("您的刷新令牌".to_string());let new_token = client .exchange_refresh_token(&refresh_token) .requ