我是spring授权服务器的新手,我想用Github登录,所以我首先尝试将client-id和client-secret放在属性文件中,但在真实的世界中,它不能存储在属性文件中,所以我试图通过ClientRegistrationRepository
接口将其存储在DB中,但在我看来,用“Github”或“Google”登录并不合适。将我重定向到GitHub或Google授权服务器的words链接
之前有人尝试过吗?请告诉我Spring Authorization Server的教程或步骤?
*问题在这张图片中,我看不到“Github”或“Google”登录与他们enter image description here
*验证码
*不确定性
<?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.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>authorization-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>authorization-server</name>
<description>authorization-server</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-security</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-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-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>
字符串
AuthorizationServerConfig.java
package com.example.authorizationserver.config.security;
import com.example.authorizationserver.providers.SuccessfulAuthenticationHandler;
import com.example.authorizationserver.services.ClientRegistrationServiceImpl;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
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.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
@EnableWebSecurity
@Configuration
@Log4j2
@AllArgsConstructor
public class AuthorizationServerConfig {
private final SuccessfulAuthenticationHandler successfulLoginWithGoogleOrGithub;
private final ClientRegistrationServiceImpl clientRegistrationService;
@Bean
@Order(1)
public SecurityFilterChain asFilterChain(HttpSecurity http) throws Exception {
// we must disable csrf for this endpoint and make it access from any one at the first filter
http.csrf(csrf -> csrf.ignoringRequestMatchers("/auth/register/**"));
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults())
.oidc(oidc -> oidc.clientRegistrationEndpoint(Customizer.withDefaults()));
http
// Resource server support that allows User Info requests to be authenticated with access tokens
// this allows me to user /userinfo endpoint in postman with access_token in the header
.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()))
.exceptionHandling(
c -> c.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
);
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain appFilterChain(HttpSecurity http) throws Exception {
// we must disable csrf for this endpoint and make it access from any one at the second filter also , because it moved from first filter to
// the second filter
http.csrf(csrf -> csrf.ignoringRequestMatchers("/auth/register/**"));
http.formLogin(Customizer.withDefaults()); // to view to user normal username and password form
// to display the word : Github to allow user to click on it to log in with username and password of Github
// and success handler to save user to db after successfully login
http.oauth2Login(oauth2Login -> oauth2Login
.clientRegistrationRepository(clientRegistrationService)
.successHandler(successfulLoginWithGoogleOrGithub));
return http.build();
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
private 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;
}
}
型
*OAuth2 ClientRegistrationEntity此实体存储有关Google或GitHub或任何提供商的凭据,我根据名为org.springframework.security.oauth2.client.registration.ClientRegistration
的类存储值
package com.example.authorizationserver.entities;
import jakarta.persistence.*;
import lombok.*;
// this entity stored credentials about Google or Github db
@Entity
@Table(name = "oauth2_clients")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class OAuth2ClientRegistrationEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String registrationId;
private String clientId;
private String clientSecret;
private String clientName;
private String authenticationMethod;
private String authorizationGrantType;
private String redirectUri;
private String scopes;
// this store provider details for simplicity
private String authorizationUri;
private String tokenUri;
private String jwkSetUri;
private String issuerUri;
private String userInfoUri;
}
型
*OAuth2 ClientRegistrationRepo用于从数据库中检索google或github凭据
package com.example.authorizationserver.repositories;
import com.example.authorizationserver.entities.OAuth2ClientRegistrationEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface OAuth2ClientRegistrationRepo extends JpaRepository<OAuth2ClientRegistrationEntity,Long> {
OAuth2ClientRegistrationEntity findByRegistrationId(String registrationId);
}
型
*ClientRegistrationServiceImpl
package com.example.authorizationserver.services;
import com.example.authorizationserver.entities.OAuth2ClientRegistrationEntity;
import com.example.authorizationserver.repositories.OAuth2ClientRegistrationRepo;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.stereotype.Service;
@Service
@Log4j2
public class ClientRegistrationServiceImpl implements ClientRegistrationRepository {
@Autowired
private OAuth2ClientRegistrationRepo oAuth2ClientRegistrationRepo;
@Override
public ClientRegistration findByRegistrationId(String registrationId) {
OAuth2ClientRegistrationEntity entity = oAuth2ClientRegistrationRepo.findByRegistrationId(registrationId);
if(entity == null) {
log.error(">>>>> NO REGISTRATION_ID FOUND WITH THIS ID = " + registrationId);
return null;
}
return this.toModel(entity);
}
private ClientRegistration toModel(OAuth2ClientRegistrationEntity entity) {
return ClientRegistration.withRegistrationId(entity.getRegistrationId())
.clientName(entity.getClientName())
.clientId(entity.getClientId())
.clientSecret(entity.getClientSecret())
.clientAuthenticationMethod(new ClientAuthenticationMethod(entity.getAuthenticationMethod()))
.authorizationGrantType(new AuthorizationGrantType(entity.getAuthorizationGrantType()))
.redirectUri(entity.getRedirectUri())
.scope(
entity.getScopes().split(",")
)
.authorizationUri(entity.getAuthorizationUri())
.tokenUri(entity.getTokenUri())
.jwkSetUri(entity.getJwkSetUri())
.issuerUri(entity.getIssuerUri())
.userInfoUri(entity.getUserInfoUri())
.build();
}
}
型
*OAuth2 ClientRegistrationTableInitializer这个类将google或github的数据添加到db中
package com.example.authorizationserver.config.db;
import com.example.authorizationserver.entities.OAuth2ClientRegistrationEntity;
import com.example.authorizationserver.repositories.OAuth2ClientRegistrationRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
@Configuration
public class OAuth2ClientRegistrationTableInitializer {
@Autowired
private OAuth2ClientRegistrationRepo oAuth2ClientRegistrationRepo;
public void addAllOAuth2ClientsToDB() {
OAuth2ClientRegistrationEntity google = OAuth2ClientRegistrationEntity.builder()
.registrationId("google")
.clientName("Google")
.clientId("my-google-client-id")
.clientSecret("my-google-client-secret")
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
.scopes("openid,profile,email,address,phone")
.authenticationMethod("client_secret_basic")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.build();
oAuth2ClientRegistrationRepo.save(google);
}
}
型
1条答案
按热度按时间kgqe7b3p1#
为了在生成的登录页面上显示链接,文档声明:
要让
DefaultLoginPageGeneratingFilter
显示已配置OAuth客户端的链接,注册的ClientRegistrationRepository
还需要实现Iterable<ClientRegistration>
。请参阅InMemoryClientRegistrationRepository
以获取参考。理想情况下,您应该提供一个自定义登录页面。