一、OAuth2.0協議
1、OAuth2.0概述
OAuth2.0是一個關於授權的開放網絡協議。
該協議在第三方應用與服務提供平台之間設置了一個授權層。第三方應用需要服務資源時,並不是直接使用用戶帳號密碼登錄服務提供平台,而是通過服務提供平台的授權層獲取token令牌,用戶可以在授權時指定token的權限范圍和有效期。第三方應用獲取到token以后,才可以訪問用戶資源。
OAuth 2.0定義了四種授權方式:
- 授權碼模式(authorization code):功能最完整、流程最嚴密的授權模式。特點是通過第三方應用的后台服務器,與服務提供平台的認證服務器進行互動獲取資源。
- 簡化模式(implicit):不通過第三方應用服務器,直接在瀏覽器中向認證服務器申請token令牌,跳過了授權碼這個步驟。所有步驟在瀏覽器中完成,token對用戶可見,且第三方應用不需要認證。
- 密碼模式(resource owner password credentials):用戶向第三方應用提供自己的用戶名和密碼。第三方應用使用這些信息,向服務提供平台索要授權。在這種模式中,用戶必須把自己的密碼給第三方應用,但是第三方應用不得儲存密碼。這通常用在用戶對第三方應用高度信任的情況下,比如第三方應用是操作系統的一部分,或者由一個著名公司出品。而認證服務器只有在其他授權模式無法執行的情況下,才能考慮使用這種模式。
- 客戶端模式(client credentials):指第三方應用以自己的名義,而不是以用戶的名義,向服務提供平台進行認證。嚴格地說,客戶端模式並不屬於OAuth框架所要解決的問題。在這種模式中,用戶直接向第三方應用注冊,第三方應用以自己的名義要求服務提供平台提供服務,其實不存在授權問題。
2、授權碼模式
假設有X用戶、A系統、B系統,X是A系統中的用戶,B系統需要訪問A系統獲取X用戶的信息。
- B系統中放置向A系統申請授權的入口;
- X用戶點擊進入A系統授權頁,如果未登錄需要登錄;
- X用戶允許授權給B系統;
- A系統重定向到B系統,並攜帶authorization_code授權碼;
- B系統使用authorization_code授權碼到A系統獲取token令牌;
- B系統可以使用token令牌到A系統獲取用戶資源。
再舉個授權碼模式的例子:某網站QQ快速登錄、賬號綁定。
- 用戶點擊網站的QQ登錄圖標
- 頁面跳轉到QQ提供的授權頁,如果PC上沒有登錄QQ賬號,需要登錄
- 用戶允許授權
- 重定向到網站回調地址,攜帶授權碼authorization_code
- 網站使用授權碼獲取token
- 使用token拉取QQ賬號信息
- 使用QQ賬號信息登錄、賬號綁定等
3、文檔和例子
百度搜索“oauth2.0”

QQ互聯官方文檔,http://wiki.connect.qq.com

二、Spring Security概述
Spring Security是一個用於快速實現Web應用安全、認證的框架,可以快速和Spring Boot整合。
開發者可以編寫配置類繼承WebSecurityConfigurerAdapter類,重寫config方法自定義登錄頁面、登錄失敗邏輯、權限不足邏輯等,並且可以編寫Filter實現更加復雜的圖片驗證碼、短信驗證碼功能。
Spring Security也可以快速實現OAuth2.0授權服務器和資源服務器。在一個Spring Boot應用中,可以使用@EnableAuthorizationServer注解實現授權服務器,使用@EnableResourceServer注解實現資源服務器。
例如
1 @SpringBootApplication 2 @EnableAuthorizationServer 3 @EnableResourceServer 4 public class BasicOauth2Application { 5 6 public static void main(String[] args) { 7 SpringApplication.run(BasicOauth2Application.class, args); 8 } 9 }
在application.properties文件配置client-id和client-secret參數
security.oauth2.client.client-id=net5ijy
security.oauth2.client.client-secret=123456
三、Spring Security實現OAuth2.0基礎
1、引入依賴
1 <parent> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-parent</artifactId> 4 <version>1.5.13.RELEASE</version> 5 </parent> 6 7 <dependencies> 8 <dependency> 9 <groupId>org.springframework.boot</groupId> 10 <artifactId>spring-boot-starter-web</artifactId> 11 </dependency> 12 <dependency> 13 <groupId>org.springframework.boot</groupId> 14 <artifactId>spring-boot-starter-security</artifactId> 15 </dependency> 16 <dependency> 17 <groupId>org.springframework.security.oauth</groupId> 18 <artifactId>spring-security-oauth2</artifactId> 19 </dependency> 20 </dependencies> 21 22 <build> 23 <plugins> 24 <plugin> 25 <groupId>org.apache.maven.plugins</groupId> 26 <artifactId>maven-compiler-plugin</artifactId> 27 <configuration> 28 <source>1.8</source> 29 <target>1.8</target> 30 <encoding>UTF-8</encoding> 31 </configuration> 32 </plugin> 33 </plugins> 34 </build>
2、Spring Boot啟動類配置
加@EnableAuthorizationServer和@EnableResourceServer注解。
1 @SpringBootApplication 2 @EnableAuthorizationServer 3 @EnableResourceServer 4 public class BasicOauth2Application { 5 6 public static void main(String[] args) { 7 SpringApplication.run(BasicOauth2Application.class, args); 8 } 9 }
3、application.properties配置
配置Security登錄用戶
security.user.name=admin
security.user.password=123456
配置client-id和client-secret參數
security.oauth2.client.client-id=net5ijy
security.oauth2.client.client-secret=123456
4、受保護資源
編寫controller
1 @RestController 2 @RequestMapping(value = "/") 3 public class TestController { 4 5 Logger log = LoggerFactory.getLogger(TestController.class); 6 7 @RequestMapping(value = "order/demo") 8 public String getDemo() { 9 Authentication auth = SecurityContextHolder.getContext() 10 .getAuthentication(); 11 log.info(auth.toString()); 12 return "Hello world"; 13 } 14 }
5、測試授權碼模式
1)獲取authorization_code授權碼
使用瀏覽器訪問:
http://localhost:7000/oauth/authorize?response_type=code&client_id=net5ijy&redirect_uri=http://localhost:8080&scope=all
地址
http://localhost:7000/oauth/authorize
參數
| response_type |
code |
| client_id |
根據實際的client-id填寫,此處寫net5ijy |
| redirect_uri |
生成code后的回調地址,http://localhost:8080 |
| scope |
權限范圍 |

登錄,使用的用戶名、密碼就是在application.properties中配置的admin和123456
security.user.name=admin
security.user.password=123456

允許授權

看到瀏覽器重定向到了http://localhost:8080並攜帶了code參數,這個code就是授權服務器生成的授權碼

2)獲取token令牌
使用curl命令獲取token令牌
curl --user net5ijy:123456 -X POST -d "grant_type=authorization_code&scope=all&redirect_uri=http%3a%2f%2flocalhost%3a8080&code=Q1dzfj" http://localhost:7000/oauth/token
地址
http://localhost:7000/oauth/token
參數
| grant_type |
授權碼模式,寫authorization_code |
| scope |
權限范圍 |
| redirect_uri |
回調地址,http://localhost:8080需要urlencode |
| code |
就是上一步生成的授權碼 |

返回值
1 { 2 "access_token": "547e258c-9c88-4130-a6d5-770b6b6ef3a4", 3 "token_type": "bearer", 4 "refresh_token": "19cf0168-913e-4f64-a766-72c0d43928ba", 5 "expires_in": 43199, 6 "scope": "all" 7 }
這樣就獲取到了token令牌,該token的訪問權限范圍是all權限,在12小時后失效。
3)使用token訪問資源
curl http://localhost:7000/order/demo?access_token=547e258c-9c88-4130-a6d5-770b6b6ef3a4

在資源url后面加上access_token參數。
6、測試密碼模式
1)獲取token令牌
使用curl命令獲取token令牌
curl --user net5ijy:123456 -X POST -d "grant_type=password&username=admin&password=123456&scope=all" http://localhost:7000/oauth/token
地址
http://localhost:7000/oauth/token
參數
| grant_type |
密碼模式,寫password |
| scope |
權限范圍 |
| username |
申請授權用戶的用戶名 |
| password |
申請授權用戶的密碼 |

返回值
1 { 2 "access_token": "20d4f648-2ce4-4198-9f2a-025211efb689", 3 "token_type": "bearer", 4 "refresh_token": "9caccc03-5b81-48f9-a32e-45538c2f779c", 5 "expires_in": 43199, 6 "scope": "all" 7 }
這樣就獲取到了token令牌,該token的訪問權限范圍是all權限,在12小時后失效。
2)使用token訪問資源
curl http://localhost:7000/order/demo?access_token=20d4f648-2ce4-4198-9f2a-025211efb689

四、Github源碼下載
https://github.com/xuguofeng/springsecurityoauth2

