springboot 集成 spring-security-oauth2-authorization-server,mysql
spring-security-oauth2
·
springboot 集成 spring-security-oauth2-authorization-server,mysql
简介
暂无
maven
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 驱动(重要) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>6.0.0.Alpha7</version>
</dependency>
代码
新建 AuthorzationServerConfig类 代码如下:
package com.example.demo.config;
import java.util.Base64;
import com.example.demo.jose.Jwks;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
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.jdbc.core.JdbcTemplate;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.OAuth2TokenFormat;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
import org.springframework.security.web.SecurityFilterChain;
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.formLogin(Customizer.withDefaults()).build();
}
//用于监管客户端的实例
@Bean
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
RegisteredClient client = RegisteredClient.withId("baidu")
.clientId("baidu")
.clientSecret("{noop}baidu")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantTypes(authorizationGrantTypes -> {
authorizationGrantTypes.add(AuthorizationGrantType.AUTHORIZATION_CODE);
authorizationGrantTypes.add(AuthorizationGrantType.REFRESH_TOKEN);
})
.tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.REFERENCE).build())
.redirectUri("https://www.baidu.com")
.build();
// Save registered client in db as if in-memory
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
registeredClientRepository.save(client);
return registeredClientRepository;
}
// @formatter:on
@Bean
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
}
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = Jwks.generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public ProviderSettings providerSettings() {
return ProviderSettings.builder().build();
}
}
新建DefaultSecurityConfig 类,代码如下
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import javax.sql.DataSource;
@Configuration
@ComponentScan
@EnableJpaRepositories
public class DefaultSecurityConfiguration {
//用户密码模式登陆
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests -> authorizeRequests
.antMatchers("/password/*").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
UserDetailsService users(DataSource dataSource){
JdbcUserDetailsManager users= new JdbcUserDetailsManager(dataSource);
UserDetails user1= User.builder().username("test1")
.password("{noop}test1")
.roles("USER")
.build();
// 这里是启动项目是自动添加一个用户,如果已经添加,可以注释
users.createUser(user1);
return users;
}
}
Jose 工具类,新建以下2个类
package com.example.demo.jose;
import java.security.KeyPair;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import javax.crypto.SecretKey;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
public final class Jwks {
private Jwks() {
}
public static RSAKey generateRsa() {
KeyPair keyPair = KeyGeneratorUtils.generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// @formatter:off
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
}
public static ECKey generateEc() {
KeyPair keyPair = KeyGeneratorUtils.generateEcKey();
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
Curve curve = Curve.forECParameterSpec(publicKey.getParams());
// @formatter:off
return new ECKey.Builder(curve, publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
}
public static OctetSequenceKey generateSecret() {
SecretKey secretKey = KeyGeneratorUtils.generateSecretKey();
// @formatter:off
return new OctetSequenceKey.Builder(secretKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
}
}
package com.example.demo.jose;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
/**
* @author Joe Grandja
* @since 0.1.0
*/
final class KeyGeneratorUtils {
private KeyGeneratorUtils() {
}
static SecretKey generateSecretKey() {
SecretKey hmacKey;
try {
hmacKey = KeyGenerator.getInstance("HmacSha256").generateKey();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return hmacKey;
}
static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
static KeyPair generateEcKey() {
EllipticCurve ellipticCurve = new EllipticCurve(
new ECFieldFp(
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951")),
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"),
new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291"));
ECPoint ecPoint = new ECPoint(
new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"),
new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
ECParameterSpec ecParameterSpec = new ECParameterSpec(
ellipticCurve,
ecPoint,
new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"),
1);
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(ecParameterSpec);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}
上面就是主要代码,下我们需要在application 中配置mysql数据源
spring.datasource.url = jdbc:mysql://localhost:3306/oauth?useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username = root
spring.datasource.password = sjz123456
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
在数据库中添加以下表
CREATE TABLE `users` (
`username` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`enabled` tinyint DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `authorities` (
`username` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`authority` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `oauth2_authorization` (
`id` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`registered_client_id` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`principal_name` varchar(200) COLLATE utf8mb4_bin NOT NULL,
`authorization_grant_type` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`attributes` blob,
`state` varchar(500) COLLATE utf8mb4_bin DEFAULT NULL,
`authorization_code_value` blob,
`authorization_code_issued_at` timestamp NULL DEFAULT NULL,
`authorization_code_expires_at` timestamp NULL DEFAULT NULL,
`authorization_code_metadata` blob,
`access_token_value` blob,
`access_token_issued_at` timestamp NULL DEFAULT NULL,
`access_token_expires_at` timestamp NULL DEFAULT NULL,
`access_token_metadata` blob,
`access_token_type` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL,
`access_token_scopes` varchar(1000) COLLATE utf8mb4_bin DEFAULT NULL,
`oidc_id_token_value` blob,
`oidc_id_token_issued_at` timestamp NULL DEFAULT NULL,
`oidc_id_token_expires_at` timestamp NULL DEFAULT NULL,
`oidc_id_token_metadata` blob,
`refresh_token_value` blob,
`refresh_token_issued_at` timestamp NULL DEFAULT NULL,
`refresh_token_expires_at` timestamp NULL DEFAULT NULL,
`refresh_token_metadata` blob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `oauth2_authorization_consent` (
`registered_client_id` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`principal_name` varchar(200) COLLATE utf8mb4_bin NOT NULL,
`authorities` varchar(1000) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`registered_client_id`,`principal_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `oauth2_registered_client` (
`id` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`client_id` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`client_secret` varchar(200) COLLATE utf8mb4_bin DEFAULT NULL,
`client_secret_expires_at` timestamp NULL DEFAULT NULL,
`client_name` varchar(200) COLLATE utf8mb4_bin NOT NULL,
`client_authentication_methods` varchar(1000) COLLATE utf8mb4_bin NOT NULL,
`authorization_grant_types` varchar(1000) COLLATE utf8mb4_bin NOT NULL,
`redirect_uris` varchar(1000) COLLATE utf8mb4_bin DEFAULT NULL,
`scopes` varchar(1000) COLLATE utf8mb4_bin NOT NULL,
`client_settings` varchar(2000) COLLATE utf8mb4_bin NOT NULL,
`token_settings` varchar(2000) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
最后运行springboot项目测试
在浏览器中输入
http://localhost:8080/oauth2/authorize?client_id=baidu&client_secret=baidu&response_type=code&redirect_uri=https://www.baidu.com
会自动跳转到 http://localhost:8080/login
在上面输入框中输入 test1, test1
点击 Sign In 按钮
页面将跳转到百度网址,注意后面有个code 参数,这个code参数后面要使用它,来获取taken
https://www.baidu.com/?code=k3Au3-YTkk28zTI0tVKAi7wW-pafFk9_WhqajI6ON1bU9LFQoRDIVPTYb5reRj7vWDtR8NhwzSaShzYZk1_Y4PHotYUPyPiW7GDH0zRZOdEPS38EVG_m912OQ1vqq1Bw
注意 这里要在header里添加 Authorization 并且将value=Basic YmFpZHU6YmFpZHU=
然后发起请求命令就可以获取 access_token
最后附上项目源码地址
https://gitee.com/sssjjjj/oauth2.git
更多推荐
已为社区贡献1条内容
所有评论(0)