diff --git a/lab-68/lab-68-demo02-authorization-server-with-client-credentials/pom.xml b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/pom.xml
new file mode 100644
index 00000000..65d8f3f0
--- /dev/null
+++ b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+ lab-68
+ cn.iocoder.springboot.labs
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ lab-68-demo02-authorization-server-with-client-credentials
+
+
+
+ 2.2.4.RELEASE
+
+ 1.8
+ 1.8
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring.boot.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+
+
+
+
+ org.springframework.security.oauth.boot
+ spring-security-oauth2-autoconfigure
+ ${spring.boot.version}
+
+
+
+
diff --git a/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/AuthorizationServerApplication.java b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/AuthorizationServerApplication.java
new file mode 100644
index 00000000..d08ae7c8
--- /dev/null
+++ b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/AuthorizationServerApplication.java
@@ -0,0 +1,13 @@
+package cn.iocoder.springboot.lab68.authorizationserverdemo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class AuthorizationServerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AuthorizationServerApplication.class, args);
+ }
+
+}
diff --git a/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/config/OAuth2AuthorizationServerConfig.java b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/config/OAuth2AuthorizationServerConfig.java
new file mode 100644
index 00000000..7a0dcebd
--- /dev/null
+++ b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/config/OAuth2AuthorizationServerConfig.java
@@ -0,0 +1,53 @@
+package cn.iocoder.springboot.lab68.authorizationserverdemo.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+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.AuthorizationServerSecurityConfigurer;
+
+/**
+ * 授权服务器配置
+ */
+@Configuration
+@EnableAuthorizationServer
+public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
+
+// /**
+// * 用户认证 Manager
+// */
+// @Autowired
+// private AuthenticationManager authenticationManager;
+//
+// @Override
+// public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
+// endpoints.authenticationManager(authenticationManager);
+// }
+
+ @Bean
+ public static NoOpPasswordEncoder passwordEncoder() {
+ return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
+ }
+
+ @Override
+ public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
+ oauthServer.checkTokenAccess("isAuthenticated()");
+// oauthServer.tokenKeyAccess("isAuthenticated()")
+// .checkTokenAccess("isAuthenticated()");
+// oauthServer.tokenKeyAccess("permitAll()")
+// .checkTokenAccess("permitAll()");
+ }
+
+ @Override
+ public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
+ clients.inMemory()
+ .withClient("clientapp").secret("112233") // Client 账号、密码。
+ .authorizedGrantTypes("client_credentials") // 客户端模式
+ .scopes("read_userinfo", "read_contacts") // 可授权的 Scope
+// .and().withClient() // 可以继续配置新的 Client
+ ;
+ }
+
+}
diff --git a/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/config/SecurityConfig.java b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/config/SecurityConfig.java
new file mode 100644
index 00000000..da9dcccc
--- /dev/null
+++ b/lab-68/lab-68-demo02-authorization-server-with-client-credentials/src/main/java/cn/iocoder/springboot/lab68/authorizationserverdemo/config/SecurityConfig.java
@@ -0,0 +1,36 @@
+package cn.iocoder.springboot.lab68.authorizationserverdemo.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.BeanIds;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+
+//@Configuration
+//@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ @Bean
+ public static NoOpPasswordEncoder passwordEncoder() {
+ return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.
+ // 使用内存中的 InMemoryUserDetailsManager
+ inMemoryAuthentication()
+ // 不使用 PasswordEncoder 密码编码器
+ .passwordEncoder(passwordEncoder())
+ // 配置 yunai 用户
+ .withUser("yunai").password("1024").roles("USER");
+ }
+
+}
diff --git a/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/config/OAuth2ResourceServerConfig.java b/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/config/OAuth2ResourceServerConfig.java
index f10fb5a9..32acfee2 100644
--- a/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/config/OAuth2ResourceServerConfig.java
+++ b/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/config/OAuth2ResourceServerConfig.java
@@ -17,6 +17,8 @@ public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter
http.authorizeRequests()
// 设置 /login 无需权限访问
.antMatchers("/login").permitAll()
+ // 设置 /client-login 无需权限访问
+ .antMatchers("/client-login").permitAll()
/// 设置 /callback 无需权限访问
.antMatchers("/callback").permitAll()
// 设置 /callback02 无需权限访问
diff --git a/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/controller/ClientLoginController.java b/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/controller/ClientLoginController.java
new file mode 100644
index 00000000..1b8e6f9c
--- /dev/null
+++ b/lab-68/lab-68-demo02-resource-server/src/main/java/cn/iocoder/springboot/lab68/resourceserverdemo/controller/ClientLoginController.java
@@ -0,0 +1,38 @@
+package cn.iocoder.springboot.lab68.resourceserverdemo.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider;
+import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/")
+public class ClientLoginController {
+
+ @Autowired
+ private OAuth2ClientProperties oauth2ClientProperties;
+
+ @Value("${security.oauth2.access-token-uri}")
+ private String accessTokenUri;
+
+ @PostMapping("/client-login")
+ public OAuth2AccessToken login() {
+ // 创建 ClientCredentialsResourceDetails 对象
+ ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
+ resourceDetails.setAccessTokenUri(accessTokenUri);
+ resourceDetails.setClientId(oauth2ClientProperties.getClientId());
+ resourceDetails.setClientSecret(oauth2ClientProperties.getClientSecret());
+ // 创建 OAuth2RestTemplate 对象
+ OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
+ restTemplate.setAccessTokenProvider(new ClientCredentialsAccessTokenProvider());
+ // 获取访问令牌
+ return restTemplate.getAccessToken();
+ }
+
+}
diff --git a/lab-68/pom.xml b/lab-68/pom.xml
index e8ca8d28..8733a1bf 100644
--- a/lab-68/pom.xml
+++ b/lab-68/pom.xml
@@ -20,6 +20,7 @@
lab-68-demo02-authorization-server-with-resource-owner-password-credentials
lab-68-demo02-authorization-server-with-authorization-code
lab-68-demo02-authorization-server-with-implicit
+ lab-68-demo02-authorization-server-with-client-credentials