在上一篇《OAuth 2.0 授權碼請求》中我們已經可以擷取到access_token了,本節将使用用戶端來通路遠端資源
配置資源伺服器
授權伺服器負責生成并發放通路令牌(access_token),用戶端在通路受保護的資源時會帶上通路令牌,資源伺服器需要解析并驗證用戶端帶的這個通路令牌。
如果你的資源伺服器同時也是一個授權伺服器(資源伺服器和授權伺服器在一起),那麼資源伺服器就不需要考慮令牌解析的事情了,否則這一步是不可或缺的。
To use the access token you need a Resource Server (which can be the same as the Authorization Server). Creating a Resource Server is easy, just add @EnableResourceServer and provide some configuration to allow the server to decode access tokens. If your application is also an Authorization Server it already knows how to decode tokens, so there is nothing else to do. If your app is a standalone service then you need to give it some more configuration.
同時,把它們放在一起的話還有一個問題需要注意,我們知道過濾器是順序執行的,是以需要確定那些通過通路令牌來通路的資源路徑不能被主過濾攔下了,需要單獨摘出來。
Note: if your Authorization Server is also a Resource Server then there is another security filter chain with lower priority controlling the API resources. Fo those requests to be protected by access tokens you need their paths not to be matched by the ones in the main user-facing filter chain, so be sure to include a request matcher that picks out only non-API resources in the WebSecurityConfigurer above.
關于Spring Security中過濾器的順序可以參見
https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/reference/htmlsingle/#filter-ordering
這裡偷個懶将它們放在一起:
package com.cjs.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);
}
/**
* 用于配置對受保護的資源的通路規則
* 預設情況下所有不在/oauth/**下的資源都是受保護的資源
* {@link OAuth2WebSecurityExpressionHandler}
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/haha/**")
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
這裡配置很簡潔,很多都用了預設的設定(比如:resourceId,accessDeniedHandler,sessionManagement等等,具體可參見源碼)
接下來,看看本例中我們被保護的資源,簡單的幾個資源(都以/haha開頭),隻為測試:
package com.cjs.example.controller;
import com.cjs.example.domain.UserInfo;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
@RequestMapping("/haha")
public class MainController {
@GetMapping("/sayHello")
public String sayHello(String name) {
return "Hello, " + name;
}
@PreAuthorize("hasAnyRole('ADMIN')")
@RequestMapping("/sayHi")
public String sayHi() {
return "hahaha";
}
@RequestMapping("/userInfo")
public UserInfo userInfo(Principal principal) {
UserInfo userInfo = new UserInfo();
userInfo.setName(principal.getName());
return userInfo;
}
}
授權伺服器配置
package com.cjs.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private RedisConnectionFactory connectionFactory;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
super.configure(security);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client-1")
.secret("$2a$10$0jyHr4rGRdQw.X9mrLkVROdQI8.qnWJ1Sl8ly.yzK0bp06aaAkL9W")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write", "execute")
.redirectUris("http://localhost:8081/login/oauth2/code/callback");
// .redirectUris("http://www.baidu.com");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
}
@Bean
public TokenStore tokenStore() {
return new RedisTokenStore(connectionFactory);
}
public static void main(String[] args) {
System.out.println(new org.apache.tomcat.util.codec.binary.Base64().encodeAsString("my-client-1:12345678".getBytes()));
System.out.println(java.util.Base64.getEncoder().encodeToString("my-client-1:12345678".getBytes()));
}
}
和之前相比,我們增加了TokenStore,将Token存儲到Redis中。否則預設放在記憶體中的話每次重新開機的話token都丢了。下面是一個例子:

application.yml如下:
server:
port: 8080
spring:
redis:
host: 127.0.0.1
port: 6379
logging:
level:
root: debug
org.springframework.web: debug
org.springframework.security: debug
WebSecurity配置
我們有了資源,有了授權,我們還缺少使用者。WebSecurity主要是配置咱們這個項目的一些安全配置,比如使用者、認證、授權等等。
package com.cjs.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("zhangsan")
.password("$2a$10$qsJ/Oy1RmUxFA.YtDT8RJ.Y2kU3U4z0jvd35YmiMOAPpD.nZUIRMC")
.roles("USER")
.and()
.withUser("lisi")
.password("$2a$10$qsJ/Oy1RmUxFA.YtDT8RJ.Y2kU3U4z0jvd35YmiMOAPpD.nZUIRMC")
.roles("USER", "ADMIN");
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/plugins/**", "/favicon.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public static void main(String[] args) {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
System.out.println(bCryptPasswordEncoder.encode("123456"));
System.out.println(bCryptPasswordEncoder.encode("12345678"));
}
}
這裡多說兩句,關于Endpoint和HttpSecurity
Endpoint
有很多端點我們是可以重寫的,比如:/login,/oauth/token等等
HttpSecurity
很多初學者可能會不知道怎麼配置HttpSecurity,這個時候其實最好的方法就是看代碼或者API文檔
下面一起看一下常見的幾個配置
我們先來看一下,當我們繼承WebSecurityConfigurerAdapter之後它的預設的HttpSecurity是怎麼配置的:
// @formatter:off
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
// @formatter:on
可以看到,所有的請求都需要授權,并且指定登入的uri是/login,同時支援Basic認證。
requestMatchers()
這個方法是用于限定隻有特定的HttpServletRequest執行個體才會導緻該HttpSecurity被調用,當然是通過請求uri進行限定的了。它後面可以接多個比對規則。例如:
@Configuration
@EnableWebSecurity
public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.antMatchers("/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
}
/* 與上面那段等價
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.and()
.requestMatchers()
.antMatchers("/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
}
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
formLogin()
該方法是用于配置登入相關的設定的。例如:
@Configuration
@EnableWebSecurity
public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin()
.usernameParameter("username") // default is username
.passwordParameter("password") // default is password
.loginPage("/authentication/login") // default is /login with an HTTP get
.failureUrl("/authentication/login?failed") // default is /login?error
.loginProcessingUrl("/authentication/login/process"); // default is /login
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
}
當我們沒有配置登入的時候,會用預設的登入,有預設的登入頁面,還有好多預設的登入配置。具體可參見 FormLoginConfigurer.loginPage(String)方法
authorizeRequests()
該方法允許基于HttpServletRequest進行通路限制,比如角色、權限。例如:
@Configuration
@EnableWebSecurity
public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/**").hasRole("USER").and().formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
.and().withUser("admin").password("password").roles("ADMIN", "USER");
}
}
anyRequest()表示比對任意請求
authenticated()表示隻有認證通過的使用者才可以通路
更多可以參見API文檔:https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/api/
用Postman通路資源
擷取授權碼
在浏覽器中輸入http://localhost:8080/oauth/authorize?response_type=code&client_id=my-client-1&redirect_uri=http://www.baidu.com&scope=read
然後跳到登入頁面,輸入使用者名和密碼登入,然後從重定向url中拿到code
換取通路令牌
通路資源
http://localhost:8080/haha/sayHi?access_token=9f908b8f-06d6-4987-b105-665ca5a4522a
{
"error": "access_denied",
"error_description": "不允許通路"
}
這裡不允許通路是因為我用zhangsan登入的,他不在ADMIN角色中
http://localhost:8080/haha/userInfo?access_token=9f908b8f-06d6-4987-b105-665ca5a4522a
{
"name": "zhangsan"
}
http://localhost:8080/haha/sayHello?name=jack&access_token=9f908b8f-06d6-4987-b105-665ca5a4522a
Hello, jack
通過用戶端程式通路資源
通路GitHub
參照SpringBoot官網的示例
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-oauth2-client
https://github.com/spring-projects
https://github.com/spring-projects/spring-boot
可以将代碼拷下來 https://github.com/spring-projects/spring-boot.git
第一步 将我們的用戶端注冊到GitHub上去
GitHub的OAuth文檔在這裡 https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
第二步 浏覽器輸入http://localhost:8080/後出現如下界面
第三步 點選任意一個連接配接,跳GitHub登入
授權以後就可以重定向到我們的localhost:8080/了
主要配置如下:
APP-CLIENT-ID: 7e304109d91ed8e9bf72
APP-CLIENT-SECRET: 003daa47fa0f350d181c8741d8bac6833aef568a
spring:
security:
oauth2:
client:
registration:
github-client-1:
client-id: ${APP-CLIENT-ID}
client-secret: ${APP-CLIENT-SECRET}
client-name: Github user
provider: github
scope: user
redirect-uri-template: http://cjshuashengke.6655.la:11664/login/oauth2/code/github
github-client-2:
client-id: ${APP-CLIENT-ID}
client-secret: ${APP-CLIENT-SECRET}
client-name: Github email
provider: github
scope: user:email
redirect-uri-template: http://cjshuashengke.6655.la:11664/login/oauth2/code/github
pom.xml如下
<?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>
<groupId>sample.oauth2.client</groupId>
<artifactId>spring-boot-sample-oauth2-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Compile -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
啟動類
package sample.oauth2.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleOAuth2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(SampleOAuth2ClientApplication.class);
}
}
ExampleController
package sample.oauth2.client;
import java.security.Principal;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExampleController {
@RequestMapping("/")
public String email(Principal principal) {
return "Hello " + principal.getName();
}
}
通路自定義的Provider
在這裡我遇到一些問題,将provider換成自己的localhost:8080就總是報錯,不知道什麼原因。
想想還是寫出來吧,希望有大神看到幫我指點迷津。。。
首先需要明确一點:Spring Security OAuth2提供了一套用戶端實作,Spring Boot也有它自己的方式。
這裡我是按照Spring Boot的那一套來的
Spring Boot最大的優點莫過于自動配置了
隻要在你的classpath下有spring-security-oauth2-client,那麼将會自動配置OAuth2 Client。
配置的屬性用的是OAuth2ClientProperties
具體參見 https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/#boot-features-security-oauth2
例如:
預設情況下,Spring Security的OAuth2LoginAuthenticationFilter隻處理URL比對/login/oauth2/code/*的請求。
如果你想自定義redirect-uri-template可以在WebSecurityConfigurerAdapter中配置。例如:
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/custom-callback");
}
}
其實,不僅僅可以自定義重定向端點,其它的比如授權端點也是可以自定義的,可參見源碼
下面重點說下我的配置
pom.xml
<?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>
<groupId>com.cjs.example</groupId>
<artifactId>cjs-oauth2-code-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cjs-oauth2-code-client</name>
<description></description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8081
spring:
security:
oauth2:
client:
registration:
my-client-1:
client-id: my-client-1
client-secret: 12345678
client-name: ABC
provider: my-oauth-provider
scope: read
redirect-uri-template: http://localhost:8081/login/oauth2/code/callback
client-authentication-method: basic
authorization-grant-type: authorization_code
provider:
my-oauth-provider:
authorization-uri: http://localhost:8080/oauth/authorize
token-uri: http://localhost:8080/oauth/token
logging:
level:
root: debug
分别啟動兩個項目
浏覽器輸入http://localhost:8080/test
點選連結ABC
輸入zhangsan/123456,結果報錯了
檢視控制台錯誤資訊
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [authorization_request_not_found]
at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:146)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:128)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
打端點,發現重定向過來的HttpServletRequest中session=null
正常情況下session不應該是null,而且屬性中還應該有一個key為org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository.AUTHORIZATION_REQUEST的屬性的
後來看根據Spring Security那一套說用@EnableOAuth2Client
利用OAuth2RestTemplate來通路資源,具體參見《Spring Security OAuth 2.0》
但是我發現加了這些問題依舊,根本問題是服務端帶着code重定向到用戶端的時候就失敗了
在用戶端收到的重定向請求中session為null
不知道大家有沒有遇到這種問題,求路過的大神們支招。。。
下面貼出用戶端完整代碼
package com.cjs.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.security.Principal;
@Controller
public class MainController {
@Autowired
private OAuth2RestTemplate oAuth2RestTemplate;
@GetMapping("/test")
public String test(Principal principal) {
return "Hello, " + principal.getName();
}
@GetMapping("/hello")
public String hello() {
return oAuth2RestTemplate.getForObject("http://localhost:8080/sayHi", String.class);
}
}
package com.cjs.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.context.annotation.Bean;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
@EnableOAuth2Client
@SpringBootApplication
public class CjsOauth2CodeClientApplication {
public static void main(String[] args) {
SpringApplication.run(CjsOauth2CodeClientApplication.class, args);
}
@Autowired
private OAuth2ClientContext oauth2ClientContext;
@Bean
public OAuth2RestTemplate restTemplate() {
return new OAuth2RestTemplate(new AuthorizationCodeResourceDetails(), oauth2ClientContext);
}
}
工程截圖
代碼上傳至 https://github.com/chengjiansheng/cjs-oauth2-example.git
參考
https://docs.spring.io/spring-security-oauth2-boot/docs/2.0.1.RELEASE/reference/pdf/spring-security-oauth2-boot-reference.pdf
https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/reference/htmlsingle/#oauth2login-advanced-login-page
https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/api/
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples
https://segmentfault.com/a/1190000012309216
https://www.jianshu.com/p/bf5dd33aea6d?utm_source=oschina-app
https://www.aliyun.com/jiaocheng/800606.html
https://blog.csdn.net/peter1220/article/details/52413250
https://blog.csdn.net/weixin_42033269/article/details/80086422