農(nóng)行一面:OAuth2 如何做權(quán)限驗(yàn)證?它有哪些模式?
OAuth2是現(xiàn)代應(yīng)用開(kāi)發(fā)中幾乎無(wú)處不在的認(rèn)證與授權(quán)協(xié)議,什么是OAuth2?它是如何工作的?OAuth2有哪些典型模式?這篇文章,我們來(lái)聊一聊。
一、什么是 OAuth2?
簡(jiǎn)單來(lái)說(shuō),OAuth2是一種授權(quán)框架,用于讓?xiě)?yīng)用程序在不暴露用戶(hù)密碼的情況下,獲得訪問(wèn)用戶(hù)受保護(hù)資源的權(quán)限。它廣泛應(yīng)用于第三方登錄、API 授權(quán)等場(chǎng)景。
二、OAuth2 的核心概念
在深入討論典型模式之前,我們先來(lái)簡(jiǎn)單了解一下OAuth2的幾個(gè)核心角色:
- 資源擁有者(Resource Owner):通常是終端用戶(hù)。
- 客戶(hù)端(Client):希望訪問(wèn)資源的應(yīng)用程序(比如你的Java應(yīng)用)。
- 資源服務(wù)器(Resource Server):存儲(chǔ)用戶(hù)資源的服務(wù)器。
- 授權(quán)服務(wù)器(Authorization Server):負(fù)責(zé)認(rèn)證和授權(quán)的服務(wù)器。
理解了這些基本概念,咱們就能更好地理解各種OAuth2的授權(quán)模式了。
三、OAuth2 的典型授權(quán)模式
OAuth2 定義了四種主要的授權(quán)模式,每種模式適用于不同的應(yīng)用場(chǎng)景。讓我們逐一來(lái)看:
1. 授權(quán)碼模式
授權(quán)碼模式(Authorization Code Grant)適用于服務(wù)器端應(yīng)用,尤其是需要訪問(wèn)用戶(hù)資源的Web應(yīng)用。
流程簡(jiǎn)述:
- 用戶(hù)訪問(wèn)客戶(hù)端(你的Java應(yīng)用)并請(qǐng)求訪問(wèn)受保護(hù)資源。
- 客戶(hù)端將用戶(hù)重定向到授權(quán)服務(wù)器,用戶(hù)在授權(quán)服務(wù)器登錄并授權(quán)。
- 授權(quán)服務(wù)器將用戶(hù)重定向回客戶(hù)端,并附帶一個(gè)授權(quán)碼。
- 客戶(hù)端使用這個(gè)授權(quán)碼向授權(quán)服務(wù)器請(qǐng)求訪問(wèn)令牌。
- 授權(quán)服務(wù)器返回訪問(wèn)令牌,客戶(hù)端使用該令牌訪問(wèn)資源服務(wù)器上的資源。
示例演示:
假設(shè)你有一個(gè)Java Spring Boot應(yīng)用,需要訪問(wèn)用戶(hù)的GitHub資源。流程如下:
@Configuration
@EnableOAuth2Client
publicclass OAuth2ClientConfig {
@Bean
public OAuth2RestTemplate githubRestTemplate(OAuth2ClientContext oauth2ClientContext) {
returnnew OAuth2RestTemplate(github(), oauth2ClientContext);
}
private OAuth2ProtectedResourceDetails github() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setClientId("your-client-id");
details.setClientSecret("your-client-secret");
details.setAccessTokenUri("https://github.com/login/oauth/access_token");
details.setUserAuthorizationUri("https://github.com/login/oauth/authorize");
details.setScope(Arrays.asList("repo", "read:user"));
return details;
}
}
在這個(gè)配置中,我們定義了如何與GitHub的OAuth2服務(wù)交互,獲取訪問(wèn)令牌并訪問(wèn)資源。
2. 隱式模式
隱式模式(Implicit Grant)適用于單頁(yè)面應(yīng)用(SPA)或移動(dòng)應(yīng)用,不適合存儲(chǔ)客戶(hù)端密鑰。
特點(diǎn):
- 直接在前端獲取訪問(wèn)令牌,省去了授權(quán)碼的步驟。
- 安全性較低,不推薦用于高安全需求的場(chǎng)景。
示例演示:
前端JavaScript代碼片段:
const clientId = 'client-id';
const redirectUri = 'https://yuanjava.com/callback';
const authUrl = `https://authorization-server.com/auth?response_type=token&client_id=${clientId}&redirect_uri=${redirectUri}&scope=read`;
window.location.href = authUrl;
// 在回調(diào)頁(yè)面獲取access_token
const hash = window.location.hash.substring(1);
const params = new URLSearchParams(hash);
const accessToken = params.get('access_token');
這種方式適用于無(wú)需在后端存儲(chǔ)敏感信息的應(yīng)用,但要注意訪問(wèn)令牌可能會(huì)暴露在前端。
3. 資源所有者密碼憑證模式
資源所有者密碼憑證模式(Resource Owner Password Credentials Grant)適用于高度信任的應(yīng)用,比如官方的移動(dòng)應(yīng)用。
特點(diǎn):
- 用戶(hù)直接提供用戶(hù)名和密碼給客戶(hù)端。
- 客戶(hù)端使用這些憑據(jù)向授權(quán)服務(wù)器請(qǐng)求訪問(wèn)令牌。
注意:這種模式下,客戶(hù)端需要處理用戶(hù)的敏感信息,風(fēng)險(xiǎn)較高。
示例演示:
public OAuth2AccessToken getAccessToken(String username, String password) {
ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();
resourceDetails.setUsername(username);
resourceDetails.setPassword(password);
resourceDetails.setAccessTokenUri("https://authorization-server.com/token");
resourceDetails.setClientId("your-client-id");
resourceDetails.setClientSecret("your-client-secret");
resourceDetails.setScope(Arrays.asList("read", "write"));
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
return restTemplate.getAccessToken();
}
在這個(gè)例子中,客戶(hù)端直接使用用戶(hù)的用戶(hù)名和密碼獲取訪問(wèn)令牌。
4. 客戶(hù)端憑證模式
客戶(hù)端憑證模式(Client Credentials Grant)適用于應(yīng)用間的通信,或后臺(tái)服務(wù)。
特點(diǎn):
- 客戶(hù)端直接使用自身的憑證(無(wú)需用戶(hù)參與)獲取訪問(wèn)令牌。
- 適合訪問(wèn)屬于客戶(hù)端自身的資源。
示例演示:
public OAuth2AccessToken getClientCredentialsToken() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setAccessTokenUri("https://authorization-server.com/token");
resourceDetails.setClientId("your-client-id");
resourceDetails.setClientSecret("your-client-secret");
resourceDetails.setScope(Arrays.asList("read", "write"));
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
return restTemplate.getAccessToken();
}
這種模式下,客戶(hù)端無(wú)需用戶(hù)授權(quán),直接獲取訪問(wèn)令牌進(jìn)行資源訪問(wèn)。
四、OAuth2 的原理
了解了各種授權(quán)模式后,我們?cè)賮?lái)看看OAuth2背后的原理,幫助你更好地理解和應(yīng)用它。
- 授權(quán)碼交換: 在授權(quán)碼模式中,授權(quán)碼是一個(gè)中間步驟,它增加了安全性。因?yàn)樵L問(wèn)令牌不直接暴露給用戶(hù)瀏覽器,防止惡意攻擊者截獲。
- 范圍(Scope)控制:OAuth2允許客戶(hù)端請(qǐng)求特定的權(quán)限范圍(Scope)。比如,你的應(yīng)用只需要讀取用戶(hù)的公開(kāi)信息,就不需要請(qǐng)求寫(xiě)入權(quán)限。這樣可以減少潛在的風(fēng)險(xiǎn)。
- 刷新令牌(Refresh Token): 訪問(wèn)令牌通常有有效期,當(dāng)過(guò)期時(shí),客戶(hù)端可以使用刷新令牌獲取新的訪問(wèn)令牌,而無(wú)需用戶(hù)重新授權(quán)。這提升了用戶(hù)體驗(yàn)和安全性。
五、實(shí)戰(zhàn)演示
為了更好地理解OAuth2,讓我們通過(guò)一個(gè)實(shí)際的例子,使用 Spring Security來(lái)實(shí)現(xiàn)OAuth2的授權(quán)碼模式。
1. 項(xiàng)目配置
首先,添加必要的依賴(lài):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
2. 配置 OAuth2 客戶(hù)端
在 application.yml 中配置OAuth2客戶(hù)端信息:
spring:
security:
oauth2:
client:
registration:
github:
client-id:client-id
client-secret:client-secret
scope:read:user,repo
redirect-uri:"{baseUrl}/login/oauth2/code/{registrationId}"
authorization-grant-type:authorization_code
client-name:GitHub
provider:
github:
authorization-uri:https://github.com/login/oauth/authorize
token-uri:https://github.com/login/oauth/access_token
user-info-uri:https://api.github.com/user
user-name-attribute:id
3. 創(chuàng)建安全配置
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(a -> a
.antMatchers("/", "/error").permitAll()
.anyRequest().authenticated()
)
.oauth2Login();
}
}
4. 創(chuàng)建控制器
@Controller
publicclass MainController {
@GetMapping("/")
public String home() {
return"home"; // 返回主頁(yè)視圖
}
@GetMapping("/user")
public String user(Model model, @AuthenticationPrincipal OAuth2User principal) {
model.addAttribute("user", principal);
return"user"; // 返回用戶(hù)信息視圖
}
}
六、總結(jié)
本文,我們深入淺出地介紹了 OAuth2的四種典型授權(quán)模式:授權(quán)碼模式、隱式模式、資源所有者密碼憑證模式以及客戶(hù)端憑證模式。OAuth2作為現(xiàn)代應(yīng)用中的核心認(rèn)證與授權(quán)框架,允許應(yīng)用在不暴露用戶(hù)密碼的情況下安全地訪問(wèn)受保護(hù)資源。