Java中OAuth2.0第三方授權(quán)原理與實戰(zhàn)
RFC6749
OAuth2的官方文檔在RFC6749:https://datatracker.ietf.org/doc/html/rfc6749
以王者榮耀請求微信登錄的過程為例
- A:Client申請訪問用戶資源
- B:用戶授權(quán)(過程較復(fù)雜)一次有效
- C:Client向Server請求一個長時間有效的token
- D:返回token
- E:使用token訪問資源
OAuth 2.0授權(quán)4大模式
授權(quán)碼模式:完整、嚴密,第三方認證和授權(quán)的最主流實現(xiàn)
- A:APP請求微信登錄
- B:用戶信息驗證
- C:返回只能使用一次的授權(quán)碼
- D:APP把授權(quán)碼發(fā)給后臺服務(wù),服務(wù)請求微信登錄請求一個長期有效的token
- E:返回長期有效的token
token只有APP的后臺服務(wù)和微信的后臺才有,二者之間使用token通信,保證數(shù)據(jù)不易泄露到后臺黑客
簡化模式:令牌用戶可見,移動端的常用實現(xiàn)手段
- A:APP請求微信登錄
- B:用戶信息驗證
- C:直接返回一個長期有效的token
密碼模式:用戶名密碼都返回
- A:用戶把用戶名 + 密碼發(fā)送給APP
- B:APP可以直接用賬號 + 密碼訪問微信后臺
客戶端模式:后臺內(nèi)容應(yīng)用之間進行訪問
微信登錄會為APP分配一個內(nèi)部的特定用戶名和密碼,APP用這個賬號 + 密碼和微信溝通,微信返回一個token,APP可以用這個token做很多部門自身的事情
合同到期后的續(xù)約機制
通常拿到Access token時還會拿到一個Refresh token,可以用來延長token的有效期
- F:token已過期
- G:使用Refresh token和微信登錄溝通,嘗試延長token
- H:重新返回一個新的token
OAuth2.0第三方授權(quán)實戰(zhàn)
oauth-client
表示王者榮耀端
pom文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>org.example</groupId> <artifactId>oauth-client</artifactId> <version>1.0-SNAPSHOT</version> <description>Demo project for Spring Boot</description> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <spring-cloud.version>2020.0.0-M5</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
SpringBoot
的經(jīng)典啟動類:
package com.wjw.oauthclient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class OauthClientApplication { public static void main(String[] args) { SpringApplication.run(OauthClientApplication.class, args); } }
創(chuàng)建OAuth2的配置類:
package com.wjw.oauthclient.config; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; //激活OAuth2 SSO客戶端 @Configuration @EnableOAuth2Sso public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest() .authenticated() .and() .csrf() .disable(); } }
配置文件application.yaml:
security.oauth2.client.client-secret=my_client_secret security.oauth2.client.client-id=my_client_id security.oauth2.client.user-authorization-uri=http://localhost:9090/oauth/authorize security.oauth2.client.access-token-uri=http://localhost:9090/oauth/token security.oauth2.resource.user-info-uri=http://localhost:9090/user server.port=8080 server.servlet.session.cookie.name=ut
- 定義用戶id為my_client_id,密碼為my_client_secret
- 定義“微信登錄服務(wù)”為:http://localhost:9090/oauth/authorize
- 請求長期有效token的地址為:http://localhost:9090/oauth/token
- 拿到token后請求用戶信息的地址為:http://localhost:9090/user
oauth-server
表示微信客戶端
pom文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>oauth-server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>oauth-server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>2020.0.0-M5</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
創(chuàng)建SpringBoot
啟動類:
package com.wjw.oauthserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; @SpringBootApplication @EnableResourceServer public class OauthServerApplication { public static void main(String[] args) { SpringApplication.run(OauthServerApplication.class, args); } }
創(chuàng)建controller:
提供一個API接口,模擬資源服務(wù)器
package com.wjw.oauthserver.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.security.Principal; @RestController public class UserController { @GetMapping("/user") public Principal getCurrentUser(Principal principal) { return principal; } }
創(chuàng)建oauth2的關(guān)鍵配置類:
package com.wjw.oauthserver.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() // 在內(nèi)存里 .withClient("my_client_id") .secret(passwordEncoder.encode("my_client_secret")) // 加密密碼 .autoApprove(true) // 允許所有子類用戶登錄 .redirectUris("http://localhost:8080/login") // 反跳會登錄頁面 .scopes("all") .accessTokenValiditySeconds(3600) .authorizedGrantTypes("authorization_code"); // 4大模式里的授權(quán)碼模式 } }
現(xiàn)在需要提供一個登錄頁面讓用戶輸入用戶名和密碼,并設(shè)置一個管理員賬戶:
package com.wjw.oauthserver.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatchers() .antMatchers("/login") .antMatchers("/oauth/authorize") .and() .authorizeRequests().anyRequest().authenticated() .and() .formLogin() .permitAll() .and() .csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("wjw") .password(passwordEncoder().encode("123456")) .roles("admin"); } }
配置文件application.yaml:
server.port=9090
分別啟動oauth-server和oauth-client進行測試:
訪問localhost:8080/hello
訪問hello時會重定向到login
訪問登錄時又會重定向到微信登錄:
之后又會重定向到:
輸入賬戶名+密碼:
繼續(xù)看控制臺:
登錄成功后還是會被重定向
此時再訪問就會有授權(quán)碼了(只能用一次):
此時瀏覽器拿著授權(quán)碼才去真正請求王者榮耀的hello接口(瀏覽器自動使用授權(quán)碼交換token,對用戶透明):
王者榮耀使用授權(quán)碼請求微信得到一個token和用戶信息并返回給瀏覽器,瀏覽器再使用這個token調(diào)王者榮耀的hello接口拿用戶信息:
到此這篇關(guān)于Java中OAuth2.0第三方授權(quán)原理與實戰(zhàn)的文章就介紹到這了,更多相關(guān)Java OAuth2.0第三方授權(quán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用sharding-jdbc實現(xiàn)水平分庫+水平分表的示例代碼
本文主要介紹了使用sharding-jdbc實現(xiàn)水平分庫+水平分表,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12Java學習關(guān)于循環(huán)和數(shù)組練習題整理
在本篇文章里小編給各位整理了關(guān)于Java學習關(guān)于循環(huán)和數(shù)組練習題相關(guān)內(nèi)容,有興趣的朋友們跟著參考學習下。2019-07-07淺談Java代理(jdk靜態(tài)代理、動態(tài)代理和cglib動態(tài)代理)
下面小編就為大家?guī)硪黄獪\談Java代理(jdk靜態(tài)代理、動態(tài)代理和cglib動態(tài)代理)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01@Transactional和@DS怎樣在事務(wù)中切換數(shù)據(jù)源
這篇文章主要介紹了@Transactional和@DS怎樣在事務(wù)中切換數(shù)據(jù)源問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07