使用 spring-security-oauth2 體驗 OAuth 2.0 的四種授權模式
目錄
-
- 第一步 訪問
GET /oauth/authorize
- 第二步 訪問
POST /oauth/authorize
- 第三步 訪問
POST /oauth/token
- 第一步 訪問
-
- 第一步 訪問
GET /oauth/authorize
- 第二步 訪問
POST /oauth/authorize
- 第一步 訪問
-
- 直接訪問
POST /oauth/token
- 直接訪問
-
- 直接訪問
POST /oauth/token
- 直接訪問
背景
一直對 OAuth 2.0
的四種授權模式比較好奇,瞭解的僅限網上的資料,沒有使用程式碼體驗過,這次使用 spring-security-oauth2
來體驗這四種模式的整個過程。
相關程式碼
pom檔案 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.0.16.RELEASE</version> <exclusions> <exclusion> <artifactId>spring-core</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>spring-context</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>spring-beans</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>spring-security-core</artifactId> <groupId>org.springframework.security</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>26.0-jre</version> </dependency> </dependencies>
配置類 @Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfigurerAdapter extends AuthorizationServerConfigurerAdapter { @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients .inMemory() .withClient("clientUser") .secret("{bcrypt}" + new BCryptPasswordEncoder().encode("123456")) .authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); UserDetails userDetails = User.withUsername("username") .password("{bcrypt}" + new BCryptPasswordEncoder().encode("password")) .roles("123") .build(); InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(userDetails); daoAuthenticationProvider.setUserDetailsService(inMemoryUserDetailsManager); AuthenticationManager authenticationManager = new ProviderManager( Lists.<AuthenticationProvider>newArrayList(daoAuthenticationProvider)); endpoints.authenticationManager(authenticationManager); } } @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public InMemoryUserDetailsManager inMemoryUserDetailsManager( SecurityProperties properties) { SecurityProperties.User user = properties.getUser(); List<String> roles = user.getRoles(); return new InMemoryUserDetailsManager(User.withUsername("user") .password("{bcrypt}" + new BCryptPasswordEncoder().encode("123456")) .roles(StringUtils.toStringArray(roles)).build()); } }
啟動類 @SpringBootApplication( exclude = UserDetailsServiceAutoConfiguration.class // excludeName = "org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration" ) public class SpringSecurityStudyApplication { public static void main(String[] args) { SpringApplication.run(SpringSecurityStudyApplication.class, args); } }
授權碼模式
第一步 訪問 GET /oauth/authorize
相關程式碼在 org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint
org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint
請求引數和返回結果如下:
返回結果在瀏覽器上展示的話,是讓使用者來勾選是否同意授權的一個頁面,還有返回結果的 _csrf
的值要作為第二步的引數。
curl如下:
curl --location --request GET 'http://127.0.0.1:8090/oauth/authorize?response_type=code&client_id=clientUser&redirect_uri=http://www.baidu.com/&scope=scope' \ --header 'Authorization: Basic dXNlcjoxMjM0NTY=' \ --header 'Cookie: JSESSIONID=AB254815273DB81F1F3BAF74E94DAAB6'
第二步 訪問 POST /oauth/authorize
相關程式碼在 org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint
crul如下:
curl --location --request POST 'http://127.0.0.1:8090/oauth/authorize?user_oauth_approval=true&scope.scope=true&_csrf=a95516db-6ce2-4033-9b81-1060b6c4d829' \ --header 'Cookie: JSESSIONID=73E846796ACB7818E09B93AC4CFD320D'
_csrf
要使用第一步返回的結果,在返回頭的 Location
裡可以得到授權碼
第一個引數必須要有,因為:
<input name="user_oauth_approval" value="true" type="hidden"/> @RequestMapping(value = "/oauth/authorize", method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL) public View approveOrDeny(@RequestParam Map<String, String> approvalParameters, Map<String, ?> model, SessionStatus sessionStatus, Principal principal) { } public static final String USER_OAUTH_APPROVAL = "user_oauth_approval";
第二個引數是使用者是否同意授權
第三步 訪問 POST /oauth/token
相關程式碼在 org.springframework.security.oauth2.provider.endpoint.TokenEndpoint
code
使用第二步的返回結果
crul如下:
curl --location --request POST 'http://127.0.0.1:8090/oauth/token' \ --header 'Authorization: Basic Y2xpZW50VXNlcjoxMjM0NTY=' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Cookie: JSESSIONID=5D41BF01BC875BDF266D3C2178537F21' \ --data-urlencode 'grant_type=authorization_code' \ --data-urlencode 'code=1pakV1' \ --data-urlencode 'redirect_uri=http://www.baidu.com/' \ --data-urlencode 'client_id=clientUser' \ --data-urlencode 'scope=scope'
簡化模式
第一步 訪問 GET /oauth/authorize
crul如下:
curl --location --request GET 'http://127.0.0.1:8090/oauth/authorize?response_type=token&client_id=clientUser&redirect_uri=http://www.baidu.com/&scope=scope' \ --header 'Authorization: Basic dXNlcjoxMjM0NTY=' \ --header 'Cookie: JSESSIONID=6AD429F6CF30C10C0E9F1A35EC78A790'
第二步 訪問 POST /oauth/authorize
crul如下:
curl --location --request POST 'http://127.0.0.1:8090/oauth/authorize?user_oauth_approval=true&scope.scope=true&_csrf=1ba6be5e-845f-47f2-9680-db613adc47c7' \ --header 'Cookie: JSESSIONID=6AD429F6CF30C10C0E9F1A35EC78A790'
密碼模式
直接訪問 POST /oauth/token
curl如下:
curl --location --request POST 'http://127.0.0.1:8090/oauth/token' \ --header 'Authorization: Basic Y2xpZW50VXNlcjoxMjM0NTY=' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Cookie: JSESSIONID=7E149951AB7D3C03E31E21450754DAAE' \ --data-urlencode 'grant_type=password' \ --data-urlencode 'username=username' \ --data-urlencode 'scope=scope' \ --data-urlencode 'password=password'
客戶端模式
直接訪問 POST /oauth/token
curl如下:
curl --location --request POST 'http://127.0.0.1:8090/oauth/token' \ --header 'Authorization: Basic Y2xpZW50VXNlcjoxMjM0NTY=' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Cookie: JSESSIONID=7E149951AB7D3C03E31E21450754DAAE' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=scope'
參考
「其他文章」
- 記一次批量更新整型型別的列 → 探究 UPDATE 的使用細節
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 執行緒池底層原理詳解與原始碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裡都有
- Django 之路由層
- 【前端必會】webpack loader 到底是什麼
- day42-反射01
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8原始碼解讀
- 詳解JS中 call 方法的實現
- 列印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 設計模式---享元模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang程式碼
- [ML從入門到入門] 支援向量機:從SVM的推導過程到SMO的收斂性討論
- 從應用訪問Pod元資料-DownwardApi的應用
- Springboot之 Mybatis 多資料來源實現
- Java 泛型程式設計
- CAS核心思想、底層實現