SpringBoot+SpringSecurity OAuth2 认证服务搭建实战 (六)OAuth2经典场景~授权码模式

系统要求

JDK17

spring-security-oauth2-authorization-server 1.3.0 以上

spring-boot-starter-oauth2-client 3.3.0 以上

Spring Boot 3.3.0 以上

修改 C:\Windows\System32\drivers\etc\hosts文件。(如果授权服务器和客户端在不同的域名下,就不用修改了)

构建授权服务

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>3.3.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.oauth.server.demo</groupId>
	<artifactId>oauth_server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>oauth_server</name>
	<description>OAuth2 Server Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>
		-->
	   <dependency>
	      <groupId>org.springframework.boot</groupId>
	      <artifactId>spring-boot-devtools</artifactId>
	      <scope>runtime</scope>
	      <optional>true</optional>
	    </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>

以上是一个完整的服务端pom内容,可以直接拿来用 

YML配置

server:
  port: 8080

spring:
  freemarker:
    template-loader-path: classpath:/templates/
    suffix: .html
    charset: UTF-8
    cache: false
    content-type: text/html
logging:
  level:
    root: info

核心代码

package com.oauth.server.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	@Order(Ordered.HIGHEST_PRECEDENCE)
	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
			throws Exception {
		
		OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
		http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
			.oidc(Customizer.withDefaults());	// Enable OpenID Connect 1.0
		http
			// Redirect to the login page when not authenticated from the
			// authorization endpoint
			.exceptionHandling((exceptions) -> exceptions
				.defaultAuthenticationEntryPointFor(
					new LoginUrlAuthenticationEntryPoint("/login"),
					new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
				)
			)
			// Accept access tokens for User Info and/or Client Registration
			.oauth2ResourceServer(resourceServer -> resourceServer
					                                  .jwt(Customizer.withDefaults()
					               ));

		return http.build();
	}

	@Bean
	@Order(2)
	public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
			throws Exception {
		http
			.authorizeHttpRequests((authorize) -> authorize.requestMatchers(HttpMethod.GET,"/login")
                                                           .permitAll()
			)
			// Form login handles the redirect to the login page from the
			// authorization server filter chain
			.formLogin(Customizer.withDefaults());
			  		
		return http.build();
	}

}

重点讲解

核心代码中配置了两个SecurityFilterChain对象,一个是处理OAuth授权的,一个是处理SpringSecurity登录的。

授权服务的相关配置和前面几章的一样,只不过不再用@Import(OAuth2AuthorizationServerConfiguration.class) 这种方式了,

因为它默认不会开启OIDC,想看代码的可以去代码仓库。

构建客户端服务

POM内容

<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>3.3.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
  <groupId>com.oauth.client.demo</groupId>
  <artifactId>oauth_client_demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>oauth_client</name>
	<description>OAuth Client Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-oauth2-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
         <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webflux</artifactId>
		</dependency>
		<dependency>
			<groupId>io.projectreactor.netty</groupId>
			<artifactId>reactor-netty</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</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>

YML配置

server: 
  port: 8010
logging:
  level:
    root: info
spring: 
  application: 
    name: oauth_client
  security:
    oauth2:
      client:
        provider:
            oauth:
              issuer-uri: http://www.oauth2server.com:8080
              #authorization-uri: http://www.oauth2server.com:8080/oauth2/authorize
              #token-uri: http://www.oauth2server.com:8080/oauth2/token
        registration:
          clientSecretBasic:
            provider: oauth
            client-id: clientid
            client-secret: client_secret
            client-authentication-method: client_secret_basic
            authorization-grant-type: client_credentials
            scope: openid,profile   
          clientSecretPost:
            provider: oauth
            client-id: clientid
            client-secret: client_secret
            client-authentication-method: client_secret_post
            authorization-grant-type: client_credentials
            scope: openid,profile
          authcode:
            provider: oauth
            client-id: clientid
            client-authentication-method: none
            authorization-grant-type: authorization_code
            scope: openid
            redirect-uri: '{baseUrl}/login/oauth2/code/authcode' 

核心代码

package com.oauth.client.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(ClientRegistrationRepository clientRegistrationRepository,HttpSecurity http) throws Exception {
		http.authorizeHttpRequests(auth->{
			      auth.anyRequest().authenticated();
			}).oauth2Client(Customizer.withDefaults())
		      .oauth2Login(Customizer.withDefaults());
		return http.build();
	}
	

}

重点讲解

yml中的认证地址都加了域名,这是因为,客户端和服务端都在同一台电脑上,如果都用localhost的话会出authorization_request_not_found的问题。

核心代码中配置了一个SecurityFilterChain,主要目的是初始OAuth2的客户端和配置OAuth2的登录。

演示效果

常见问题

如果你在同一台电脑上启动的客户端和服务端,都用的localhost访问的话。会遇到下面这个问题:

这时候只要配置一下hosts文件:127.0.0.1 www.oauth2server.com

再把客户端的yml配置改成域名就行了。

代码地址

完整代码参考地址:demo_03

以上只是一篇以讲解怎样以最简单的方式搭建OAuth2授权码服务。其中还有很多细节,比如

  1. 为什么授权码模式要开启OIDC ?
  2. 为什么回调地址是{baseUrl}/login/oauth2/code/authcode ?
  3. 怎么配置自己的登录页面和协议页面?
  4. 授权码模式中的code_challenge是做什么的?

等等,这些都会在后面的章节一一解答。敬请期待!

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

觉自性本然

您的鼓励与支持是我最大的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值