本篇文章讓我?guī)阏J(rèn)識一下什么是oauth協(xié)議
什么是 oauth協(xié)議 ?
百度百科上解釋:允許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務(wù)提供者的數(shù)據(jù)。每一個令牌授權(quán)一個特定的網(wǎng)站(例如,視頻編輯網(wǎng)站)在特定的時段(例如,接下來的2小時內(nèi))內(nèi)訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth允許用戶授權(quán)第三方網(wǎng)站訪問他們存儲在另外的服務(wù)提供者上的信息,而不需要分享他們的訪問許可或他們數(shù)據(jù)的所有內(nèi)容。
簡單的來講就是一個令牌,這個令牌可以有一定的權(quán)限,在不知道用戶密碼的情況下也可以進行部分的功功能操作。用一個例子幫助理解:一個甲方公司,公司里面使用一卡通,這張卡可以門禁,食堂,等等,公司招了外包進來,外包只能開通門禁就行,其他的權(quán)限是沒有的。這時候公司就不會給一張正式員工的卡,而是外包的卡,正編員工卡就是用戶的賬號密碼,這個外包卡就相當(dāng)于是一個令牌,并且可能公司會給你的外包卡設(shè)置一個有效期,等有效期快到的時候有需要申請延期。這個就相當(dāng)于是oauth協(xié)議模式。用戶不會給你用戶名和密碼,那樣相當(dāng)于放開了所有的權(quán)限,而會給你提供一個令牌,在有效期類可以訪問特定的功能服務(wù) 使用令牌的優(yōu)點:
- 令牌是短期的,到期會自動失效,用戶自己無法修改。密碼一般長期有效,用戶不修改,就不會發(fā)生變化。
- 令牌可以被數(shù)據(jù)所有者撤銷,會立即失效。
- 令牌有權(quán)限范圍(scope),對于網(wǎng)絡(luò)服務(wù)來說,只讀令牌就比讀寫令牌更安全。密碼一般是完整權(quán)限
oauth協(xié)議有四種模式;
1、授權(quán)碼模式 2、隱藏式 3、密碼式 4、客戶端憑證 其中授權(quán)碼方式是最常用的流程,安全性也最高,今天我們就來著重講一下授權(quán)碼模式。 授權(quán)碼模式: 指的是第三方應(yīng)用先申請一個授權(quán)碼,然后再用該碼獲取令牌,授權(quán)碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務(wù)器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。
授權(quán)碼模式主要分為幾個步驟
以甲方公司員工卡系統(tǒng)(SelfResearch.com)和外包公司員工卡系統(tǒng)(outsource.com)為例,下面是授權(quán)碼模式的流程
請求授權(quán)碼
首先,甲方公司給外包員工方提供一個授權(quán)鏈接,外包員工點擊連接,申請授權(quán)碼,連接參數(shù)如下所示
https://SelfResearch.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
response_type參數(shù)表示要求返回授權(quán)碼(code), client_id參數(shù)讓 甲方 知道是誰在請求, redirect_uri參數(shù)是 甲方系統(tǒng) 接受或拒絕請求后的跳轉(zhuǎn)網(wǎng)址, scope參數(shù)表示要求的授權(quán)范圍(這里是只讀)。
返回授權(quán)碼
用戶跳轉(zhuǎn)到這個之后,甲方公司會先要求用戶登錄,然后請求授權(quán),如果同意就跳轉(zhuǎn)到redirect_uri這個參數(shù)的地址,并返回授權(quán)碼
https://SelfResearch.com/callback?code=AUTHORIZATION_CODE
code就是表示授權(quán)碼
請求令牌
外包員工拿著授權(quán)碼去請求令牌
https://SelfResearch.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL
- client_id參數(shù)和client_secret參數(shù)用來讓 甲方公司 確認(rèn) 外包員工 的身份(client_secret參數(shù)是保密的,因此只能在后端發(fā)請求)。
- grant_type參數(shù)的值是AUTHORIZATION_CODE,表示采用的授權(quán)方式是授權(quán)碼。
- code參數(shù)是上一步拿到的授權(quán)碼。
- redirect_uri參數(shù)是令牌頒發(fā)后的回調(diào)網(wǎng)址。
返回令牌 外包員工訪問redirect_uri會得到一串json數(shù)據(jù):
{
"access_token": "67c4051b-36c8-11ec-af33-00163e0808bf",
"token_type": "bearer",
"refresh_token": "71975ccc-36c8-11ec-af33-cfd2826915e5",
"expires_in": 3249,
"scope": "read"
}
access_token就是令牌了,用戶需要訪問其他接口就需要帶上這個token去訪問了 refresh_token這個是刷新令牌,如果需要使用新的token,就需要通過這個刷新令牌來獲取最新的access_token。
實現(xiàn) oauth2,可以分為三個步驟
- 認(rèn)證服務(wù)
- 資源服務(wù)
- 第三方服務(wù)
現(xiàn)在第三方用戶(test9527)想去訪問資源中的部分功能(接口),但是改功能只有User角色才能訪問,需要先通過認(rèn)證服務(wù)器獲取user的授權(quán)碼,然后拿著這個code和自己賬號信息去獲取token,并校驗通過之后才能訪問到資源服務(wù)器,也就是第三方用戶通過 test9527 可以訪問本來需要user權(quán)限才能訪問的資源功能(接口)
實現(xiàn)步驟:
創(chuàng)建三個服務(wù)oauth-server(認(rèn)證服務(wù))、resource-server(資源服務(wù))、third-server(第三方服務(wù)
maven依賴
< !-- oauth2 -- >
< dependency >
< groupId >org.springframework.security.oauth< /groupId >
< artifactId >spring-security-oauth2< /artifactId >
< version >2.1.3.RELEASE< /version >
< /dependency >
< !-- spring security-- >
< dependency >
< groupId >org.springframework.boot< /groupId >
< artifactId >spring-boot-starter-security< /artifactId >
< /dependency >
oauth-server 服務(wù)配置文件
/**
* 模擬第三方授權(quán)配置
*/
@EnableAuthorizationServer
@Configuration
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Resource
ClientDetailsService clientDetailsService;
/**
* 資源服務(wù)器校驗Token
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
}
/**
* 第三方客戶端請求配置,和資源服務(wù)訪問的配置,不設(shè)置默認(rèn)都可以訪問,提供默認(rèn)回調(diào)地址
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//第三方用戶
.withClient("test9527")
.secret(new BCryptPasswordEncoder().encode("test9527"))
.resourceIds("resource")
//認(rèn)證模式
.authorizedGrantTypes("authorization_code","refresh_token")
.scopes("all")
//回調(diào)地址
.redirectUris("http://localhost:8082/notify.html");
}
/**
* 配置訪問端點
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authorizationCodeServices(authorizationCodeServices()).tokenServices(tokenServices());
}
/**
* 內(nèi)存管理
*/
@Bean
AuthorizationCodeServices authorizationCodeServices() {
return new InMemoryAuthorizationCodeServices();
}
/**
* Token管理規(guī)則
*/
@Bean
AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
services.setClientDetailsService(clientDetailsService);
services.setSupportRefreshToken(true);
services.setTokenStore(tokenStore());
services.setAccessTokenValiditySeconds(3600);
services.setRefreshTokenValiditySeconds(3600*7);
return services;
}
@Bean
TokenStore tokenStore() {
return new InMemoryTokenStore();
}
配置spring security
/**
* 模擬本地用戶配置
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 密碼加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 內(nèi)存中虛擬用戶和角色
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("user");
}
/**
* 表單登錄
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().formLogin();
}
}
resource-server配置
/**
* 資源服務(wù)管理配置
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
/**
* Token令牌校驗
*/
@Bean
RemoteTokenServices tokenServices() {
RemoteTokenServices services = new RemoteTokenServices();
services.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
services.setClientId("test9527");
services.setClientSecret("test9527");
return services;
}
/**
* 服務(wù)資源ID配置
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("resource").tokenServices(tokenServices());
}
/**
* 模擬用戶權(quán)限規(guī)則
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//訪問user下的路徑需要user角色
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated();
}
resource下的功能(接口)
第三方服務(wù)首先認(rèn)證,獲取授權(quán)碼code http://localhost:8080/oauth/authorize?client_id=test9527&response_type=code&scope=all&redirect_uri=http://localhost:8082/notify.html
此時會到認(rèn)證服務(wù)器中的user認(rèn)證
此時需要user用戶同意授權(quán),當(dāng)認(rèn)證服務(wù)中的user用戶同意之后,到如下頁面,此時看接口可以知道已經(jīng)拿到code授權(quán)碼,并跳轉(zhuǎn)到我們需要跳轉(zhuǎn)的地址
redirect_uri=http://localhost:8082/notify.html
拿到授權(quán)碼之后訪問回調(diào)地址 http://localhost:8082/notify.html?code=Rs067L
然后通過code,client_id,client_secret 等參數(shù)訪問獲取令牌地址 https://SelfResearch.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=SMD5nj&redirect_uri=redirect_uri=http://localhost:8082/notify.html
成功之后會返回token,刷新token,以及token有效時間,如下
拿到token之后,我們再去訪問資源服務(wù)器,此時就能順利訪問到功能(接口)了
最終效果,最終第三方用戶test9527訪問當(dāng)了資源服務(wù)器功
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7002瀏覽量
88940 -
參數(shù)
+關(guān)注
關(guān)注
11文章
1829瀏覽量
32194
發(fā)布評論請先 登錄
相關(guān)推薦
評論