首页 > 其他分享 >如何使用JPA实现Spring 授权服务器的核心服务

如何使用JPA实现Spring 授权服务器的核心服务

时间:2022-12-07 10:02:19浏览次数:41  
标签:return String JPA Spring private entity varchar 服务器 NULL

如何使用JPA实现Spring 授权服务器的核心服务_ide

本指南展示了如何使用JPA实现Spring 授权服务器​的核心服务。 本指南的目的是提供自己实现这些服务的起点,以便您可以根据需要进行修改。

  • 定义数据模型
  • 创建 JPA 实体
  • 创建 Spring 数据存储库
  • 实施核心服务

定义数据模型

本指南提供了数据模型的起点,并使用了最简单的结构和数据类型。 为了提出初始架构,我们首先查看核心服务使用的域对象。

除了令牌、状态、元数据、设置和声明值之外,我们对所有列使用 JPA 默认列长度 255。 实际上,您可能需要自定义您使用的列的长度甚至类型。 建议你在部署到生产环境之前进行试验和测试。

  • 客户端架构
  • 授权架构
  • 授权同意架构

客户端架构

RegisterClient域对象包含一些多值字段和一些需要存储任意键/值数据的设置字段。 以下清单显示了架构。​​client​

客户端架构

CREATE TABLE client (
id varchar(255) NOT NULL,
clientId varchar(255) NOT NULL,
clientIdIssuedAt timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
clientSecret varchar(255) DEFAULT NULL,
clientSecretExpiresAt timestamp DEFAULT NULL,
clientName varchar(255) NOT NULL,
clientAuthenticationMethods varchar(1000) NOT NULL,
authorizationGrantTypes varchar(1000) NOT NULL,
redirectUris varchar(1000) DEFAULT NULL,
scopes varchar(1000) NOT NULL,
clientSettings varchar(2000) NOT NULL,
tokenSettings varchar(2000) NOT NULL,
PRIMARY KEY (id)
);

授权架构

OAuth2Authorization域对象更为复杂,包含多个多值字段以及大量任意长的令牌值、元数据、设置和声明值。 内置的 JDBC 实现利用扁平化结构,该结构更喜欢性能而不是规范化,我们在这里也采用这种结构。

很难找到一种在所有情况下和所有数据库供应商都能正常工作的扁平数据库模式。 您可能需要根据需要规范化或大量更改以下架构。

以下清单显示了架构。​​authorization​

授权架构

CREATE TABLE authorization (
id varchar(255) NOT NULL,
registeredClientId varchar(255) NOT NULL,
principalName varchar(255) NOT NULL,
authorizationGrantType varchar(255) NOT NULL,
attributes varchar(4000) DEFAULT NULL,
state varchar(500) DEFAULT NULL,
authorizationCodeValue varchar(4000) DEFAULT NULL,
authorizationCodeIssuedAt timestamp DEFAULT NULL,
authorizationCodeExpiresAt timestamp DEFAULT NULL,
authorizationCodeMetadata varchar(2000) DEFAULT NULL,
accessTokenValue varchar(4000) DEFAULT NULL,
accessTokenIssuedAt timestamp DEFAULT NULL,
accessTokenExpiresAt timestamp DEFAULT NULL,
accessTokenMetadata varchar(2000) DEFAULT NULL,
accessTokenType varchar(255) DEFAULT NULL,
accessTokenScopes varchar(1000) DEFAULT NULL,
refreshTokenValue varchar(4000) DEFAULT NULL,
refreshTokenIssuedAt timestamp DEFAULT NULL,
refreshTokenExpiresAt timestamp DEFAULT NULL,
refreshTokenMetadata varchar(2000) DEFAULT NULL,
oidcIdTokenValue varchar(4000) DEFAULT NULL,
oidcIdTokenIssuedAt timestamp DEFAULT NULL,
oidcIdTokenExpiresAt timestamp DEFAULT NULL,
oidcIdTokenMetadata varchar(2000) DEFAULT NULL,
oidcIdTokenClaims varchar(2000) DEFAULT NULL,
PRIMARY KEY (id)
);

授权同意架构

OAuth2AuthorizationConsent域对象是最容易建模的,除了组合键外,还只包含一个多值字段。 以下清单显示了架构。​​authorizationConsent​

授权同意架构

CREATE TABLE authorizationConsent (
registeredClientId varchar(255) NOT NULL,
principalName varchar(255) NOT NULL,
authorities varchar(1000) NOT NULL,
PRIMARY KEY (registeredClientId, principalName)
);

创建 JPA 实体

前面的架构示例为我们需要创建的实体的结构提供了参考。

以下实体是最少注释的,只是示例。 它们允许动态创建架构,因此不需要手动执行上述 sql 脚本。

  • 客户实体
  • 授权实体
  • 授权同意实体

客户实体

下面的清单显示了实体,该实体用于保存从Registered Client域对象映射的信息。​​Client​

客户实体

@Entity
@Table(name = "`client`")
public class Client {
@Id
private String id;
private String clientId;
private Instant clientIdIssuedAt;
private String clientSecret;
private Instant clientSecretExpiresAt;
private String clientName;
@Column(length = 1000)
private String clientAuthenticationMethods;
@Column(length = 1000)
private String authorizationGrantTypes;
@Column(length = 1000)
private String redirectUris;
@Column(length = 1000)
private String scopes;
@Column(length = 2000)
private String clientSettings;
@Column(length = 2000)
private String tokenSettings;

}

授权实体

下面的清单显示了实体,该实体用于保存从OAuth2Authorization域对象映射的信息。​​Authorization​

授权实体

@Entity
@Table(name = "`authorization`")
public class Authorization {
@Id
@Column
private String id;
private String registeredClientId;
private String principalName;
private String authorizationGrantType;
@Column(length = 1000)
private String authorizedScopes;
@Column(length = 4000)
private String attributes;
@Column(length = 500)
private String state;

@Column(length = 4000)
private String authorizationCodeValue;
private Instant authorizationCodeIssuedAt;
private Instant authorizationCodeExpiresAt;
private String authorizationCodeMetadata;

@Column(length = 4000)
private String accessTokenValue;
private Instant accessTokenIssuedAt;
private Instant accessTokenExpiresAt;
@Column(length = 2000)
private String accessTokenMetadata;
private String accessTokenType;
@Column(length = 1000)
private String accessTokenScopes;

@Column(length = 4000)
private String refreshTokenValue;
private Instant refreshTokenIssuedAt;
private Instant refreshTokenExpiresAt;
@Column(length = 2000)
private String refreshTokenMetadata;

@Column(length = 4000)
private String oidcIdTokenValue;
private Instant oidcIdTokenIssuedAt;
private Instant oidcIdTokenExpiresAt;
@Column(length = 2000)
private String oidcIdTokenMetadata;
@Column(length = 2000)
private String oidcIdTokenClaims;

}

授权同意实体

下面的清单显示了实体,该实体用于保存从OAuth2AuthorizationConsent域对象映射的信息。​​AuthorizationConsent​

授权同意实体

@Entity
@Table(name = "`authorizationConsent`")
@IdClass(AuthorizationConsent.AuthorizationConsentId.class)
public class AuthorizationConsent {
@Id
private String registeredClientId;
@Id
private String principalName;
@Column(length = 1000)
private String authorities;

public static class AuthorizationConsentId implements Serializable {
private String registeredClientId;
private String principalName;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AuthorizationConsentId that = (AuthorizationConsentId) o;
return registeredClientId.equals(that.registeredClientId) && principalName.equals(that.principalName);
}

@Override
public int hashCode() {
return Objects.hash(registeredClientId, principalName);
}
}
}

创建 Spring 数据存储库

通过仔细检查每个核心服务的接口并查看实现,我们可以派生出支持每个接口的 JPA 版本所需的最少查询集。​​Jdbc​

  • 客户端存储库
  • 授权存储库
  • 授权同意存储库

客户端存储库

下面的清单显示了,它能够通过 andfields 找到客户端。​​ClientRepository​​​​id​​​​clientId​

客户端存储库

@Repository
public interface ClientRepository extends JpaRepository<Client, String> {
Optional<Client> findByClientId(String clientId);
}

授权存储库

下面的清单显示了 ,它能够找到授权字段以及,,和令牌字段。 它还允许查询令牌字段的组合。​​AuthorizationRepository​​​​id​​​​state​​​​authorizationCodeValue​​​​accessTokenValue​​​​refreshTokenValue​

授权存储库

@Repository
public interface AuthorizationRepository extends JpaRepository<Authorization, String> {
Optional<Authorization> findByState(String state);
Optional<Authorization> findByAuthorizationCodeValue(String authorizationCode);
Optional<Authorization> findByAccessTokenValue(String accessToken);
Optional<Authorization> findByRefreshTokenValue(String refreshToken);
@Query("select a from Authorization a where a.state = :token" +
" or a.authorizationCodeValue = :token" +
" or a.accessTokenValue = :token" +
" or a.refreshTokenValue = :token"
)
Optional<Authorization> findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(@Param("token") String token);
}

授权同意存储库

下面的清单显示了 ,它能够通过形成复合主键的 andfields 查找和删除授权同意。​​AuthorizationConsentRepository​​​​registeredClientId​​​​principalName​

授权同意存储库

@Repository
public interface AuthorizationConsentRepository extends JpaRepository<AuthorizationConsent, AuthorizationConsent.AuthorizationConsentId> {
Optional<AuthorizationConsent> findByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName);
void deleteByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName);
}

实施核心服务

有了上述实体和存储库,我们可以开始实施核心服务。 通过查看实现,我们可以派生一组最小的内部实用程序,用于在枚举的字符串值之间转换,以及读取和写入属性、设置、元数据和声明字段的 JSON 数据。​​Jdbc​

请记住,将 JSON 数据写入具有固定长度的文本列已被证明在实现中存在问题。 虽然这些示例继续这样做,但您可能需要将这些字段拆分为支持任意长数据值的单独表或数据存储。​​Jdbc​

  • 已注册的客户端存储库
  • 授权服务
  • 授权同意服务

已注册的客户端存储库

下面的清单显示了 ,它使用ClientRepository来持久化客户端,并映射到 RegisterClient 域对象和从Registered Client域对象映射。​​JpaRegisteredClientRepository​

​RegisteredClientRepository​​实现

@Component
public class JpaRegisteredClientRepository implements RegisteredClientRepository {
private final ClientRepository clientRepository;
private final ObjectMapper objectMapper = new ObjectMapper();

public JpaRegisteredClientRepository(ClientRepository clientRepository) {
Assert.notNull(clientRepository, "clientRepository cannot be null");
this.clientRepository = clientRepository;

ClassLoader classLoader = JpaRegisteredClientRepository.class.getClassLoader();
List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
this.objectMapper.registerModules(securityModules);
this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
}

@Override
public void save(RegisteredClient registeredClient) {
Assert.notNull(registeredClient, "registeredClient cannot be null");
this.clientRepository.save(toEntity(registeredClient));
}

@Override
public RegisteredClient findById(String id) {
Assert.hasText(id, "id cannot be empty");
return this.clientRepository.findById(id).map(this::toObject).orElse(null);
}

@Override
public RegisteredClient findByClientId(String clientId) {
Assert.hasText(clientId, "clientId cannot be empty");
return this.clientRepository.findByClientId(clientId).map(this::toObject).orElse(null);
}

private RegisteredClient toObject(Client client) {
Set<String> clientAuthenticationMethods = StringUtils.commaDelimitedListToSet(
client.getClientAuthenticationMethods());
Set<String> authorizationGrantTypes = StringUtils.commaDelimitedListToSet(
client.getAuthorizationGrantTypes());
Set<String> redirectUris = StringUtils.commaDelimitedListToSet(
client.getRedirectUris());
Set<String> clientScopes = StringUtils.commaDelimitedListToSet(
client.getScopes());

RegisteredClient.Builder builder = RegisteredClient.withId(client.getId())
.clientId(client.getClientId())
.clientIdIssuedAt(client.getClientIdIssuedAt())
.clientSecret(client.getClientSecret())
.clientSecretExpiresAt(client.getClientSecretExpiresAt())
.clientName(client.getClientName())
.clientAuthenticationMethods(authenticationMethods ->
clientAuthenticationMethods.forEach(authenticationMethod ->
authenticationMethods.add(resolveClientAuthenticationMethod(authenticationMethod))))
.authorizationGrantTypes((grantTypes) ->
authorizationGrantTypes.forEach(grantType ->
grantTypes.add(resolveAuthorizationGrantType(grantType))))
.redirectUris((uris) -> uris.addAll(redirectUris))
.scopes((scopes) -> scopes.addAll(clientScopes));

Map<String, Object> clientSettingsMap = parseMap(client.getClientSettings());
builder.clientSettings(ClientSettings.withSettings(clientSettingsMap).build());

Map<String, Object> tokenSettingsMap = parseMap(client.getTokenSettings());
builder.tokenSettings(TokenSettings.withSettings(tokenSettingsMap).build());

return builder.build();
}

private Client toEntity(RegisteredClient registeredClient) {
List<String> clientAuthenticationMethods = new ArrayList<>(registeredClient.getClientAuthenticationMethods().size());
registeredClient.getClientAuthenticationMethods().forEach(clientAuthenticationMethod ->
clientAuthenticationMethods.add(clientAuthenticationMethod.getValue()));

List<String> authorizationGrantTypes = new ArrayList<>(registeredClient.getAuthorizationGrantTypes().size());
registeredClient.getAuthorizationGrantTypes().forEach(authorizationGrantType ->
authorizationGrantTypes.add(authorizationGrantType.getValue()));

Client entity = new Client();
entity.setId(registeredClient.getId());
entity.setClientId(registeredClient.getClientId());
entity.setClientIdIssuedAt(registeredClient.getClientIdIssuedAt());
entity.setClientSecret(registeredClient.getClientSecret());
entity.setClientSecretExpiresAt(registeredClient.getClientSecretExpiresAt());
entity.setClientName(registeredClient.getClientName());
entity.setClientAuthenticationMethods(StringUtils.collectionToCommaDelimitedString(clientAuthenticationMethods));
entity.setAuthorizationGrantTypes(StringUtils.collectionToCommaDelimitedString(authorizationGrantTypes));
entity.setRedirectUris(StringUtils.collectionToCommaDelimitedString(registeredClient.getRedirectUris()));
entity.setScopes(StringUtils.collectionToCommaDelimitedString(registeredClient.getScopes()));
entity.setClientSettings(writeMap(registeredClient.getClientSettings().getSettings()));
entity.setTokenSettings(writeMap(registeredClient.getTokenSettings().getSettings()));

return entity;
}

private Map<String, Object> parseMap(String data) {
try {
return this.objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {
});
} catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
}

private String writeMap(Map<String, Object> data) {
try {
return this.objectMapper.writeValueAsString(data);
} catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
}

private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) {
if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.AUTHORIZATION_CODE;
} else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.CLIENT_CREDENTIALS;
} else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.REFRESH_TOKEN;
}
return new AuthorizationGrantType(authorizationGrantType); // Custom authorization grant type
}

private static ClientAuthenticationMethod resolveClientAuthenticationMethod(String clientAuthenticationMethod) {
if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
} else if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.CLIENT_SECRET_POST;
} else if (ClientAuthenticationMethod.NONE.getValue().equals(clientAuthenticationMethod)) {
return ClientAuthenticationMethod.NONE;
}
return new ClientAuthenticationMethod(clientAuthenticationMethod); // Custom client authentication method
}
}

授权服务

下面的清单显示了 ,它使用AuthorizationRepository来持久保存授权,并映射到 OAuth2Authorization 域对象和从OAuth2Authorization域对象映射。​​JpaOAuth2AuthorizationService​

​OAuth2AuthorizationService​​实现

@Component
public class JpaOAuth2AuthorizationService implements OAuth2AuthorizationService {
private final AuthorizationRepository authorizationRepository;
private final RegisteredClientRepository registeredClientRepository;
private final ObjectMapper objectMapper = new ObjectMapper();

public JpaOAuth2AuthorizationService(AuthorizationRepository authorizationRepository, RegisteredClientRepository registeredClientRepository) {
Assert.notNull(authorizationRepository, "authorizationRepository cannot be null");
Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
this.authorizationRepository = authorizationRepository;
this.registeredClientRepository = registeredClientRepository;

ClassLoader classLoader = JpaOAuth2AuthorizationService.class.getClassLoader();
List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
this.objectMapper.registerModules(securityModules);
this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
}

@Override
public void save(OAuth2Authorization authorization) {
Assert.notNull(authorization, "authorization cannot be null");
this.authorizationRepository.save(toEntity(authorization));
}

@Override
public void remove(OAuth2Authorization authorization) {
Assert.notNull(authorization, "authorization cannot be null");
this.authorizationRepository.deleteById(authorization.getId());
}

@Override
public OAuth2Authorization findById(String id) {
Assert.hasText(id, "id cannot be empty");
return this.authorizationRepository.findById(id).map(this::toObject).orElse(null);
}

@Override
public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {
Assert.hasText(token, "token cannot be empty");

Optional<Authorization> result;
if (tokenType == null) {
result = this.authorizationRepository.findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(token);
} else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) {
result = this.authorizationRepository.findByState(token);
} else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) {
result = this.authorizationRepository.findByAuthorizationCodeValue(token);
} else if (OAuth2ParameterNames.ACCESS_TOKEN.equals(tokenType.getValue())) {
result = this.authorizationRepository.findByAccessTokenValue(token);
} else if (OAuth2ParameterNames.REFRESH_TOKEN.equals(tokenType.getValue())) {
result = this.authorizationRepository.findByRefreshTokenValue(token);
} else {
result = Optional.empty();
}

return result.map(this::toObject).orElse(null);
}

private OAuth2Authorization toObject(Authorization entity) {
RegisteredClient registeredClient = this.registeredClientRepository.findById(entity.getRegisteredClientId());
if (registeredClient == null) {
throw new DataRetrievalFailureException(
"The RegisteredClient with id '" + entity.getRegisteredClientId() + "' was not found in the RegisteredClientRepository.");
}

OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient)
.id(entity.getId())
.principalName(entity.getPrincipalName())
.authorizationGrantType(resolveAuthorizationGrantType(entity.getAuthorizationGrantType()))
.authorizedScopes(StringUtils.commaDelimitedListToSet(entity.getAuthorizedScopes()))
.attributes(attributes -> attributes.putAll(parseMap(entity.getAttributes())));
if (entity.getState() != null) {
builder.attribute(OAuth2ParameterNames.STATE, entity.getState());
}

if (entity.getAuthorizationCodeValue() != null) {
OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(
entity.getAuthorizationCodeValue(),
entity.getAuthorizationCodeIssuedAt(),
entity.getAuthorizationCodeExpiresAt());
builder.token(authorizationCode, metadata -> metadata.putAll(parseMap(entity.getAuthorizationCodeMetadata())));
}

if (entity.getAccessTokenValue() != null) {
OAuth2AccessToken accessToken = new OAuth2AccessToken(
OAuth2AccessToken.TokenType.BEARER,
entity.getAccessTokenValue(),
entity.getAccessTokenIssuedAt(),
entity.getAccessTokenExpiresAt(),
StringUtils.commaDelimitedListToSet(entity.getAccessTokenScopes()));
builder.token(accessToken, metadata -> metadata.putAll(parseMap(entity.getAccessTokenMetadata())));
}

if (entity.getRefreshTokenValue() != null) {
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(
entity.getRefreshTokenValue(),
entity.getRefreshTokenIssuedAt(),
entity.getRefreshTokenExpiresAt());
builder.token(refreshToken, metadata -> metadata.putAll(parseMap(entity.getRefreshTokenMetadata())));
}

if (entity.getOidcIdTokenValue() != null) {
OidcIdToken idToken = new OidcIdToken(
entity.getOidcIdTokenValue(),
entity.getOidcIdTokenIssuedAt(),
entity.getOidcIdTokenExpiresAt(),
parseMap(entity.getOidcIdTokenClaims()));
builder.token(idToken, metadata -> metadata.putAll(parseMap(entity.getOidcIdTokenMetadata())));
}

return builder.build();
}

private Authorization toEntity(OAuth2Authorization authorization) {
Authorization entity = new Authorization();
entity.setId(authorization.getId());
entity.setRegisteredClientId(authorization.getRegisteredClientId());
entity.setPrincipalName(authorization.getPrincipalName());
entity.setAuthorizationGrantType(authorization.getAuthorizationGrantType().getValue());
entity.setAuthorizedScopes(StringUtils.collectionToDelimitedString(authorization.getAuthorizedScopes(), ","));
entity.setAttributes(writeMap(authorization.getAttributes()));
entity.setState(authorization.getAttribute(OAuth2ParameterNames.STATE));

OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode =
authorization.getToken(OAuth2AuthorizationCode.class);
setTokenValues(
authorizationCode,
entity::setAuthorizationCodeValue,
entity::setAuthorizationCodeIssuedAt,
entity::setAuthorizationCodeExpiresAt,
entity::setAuthorizationCodeMetadata
);

OAuth2Authorization.Token<OAuth2AccessToken> accessToken =
authorization.getToken(OAuth2AccessToken.class);
setTokenValues(
accessToken,
entity::setAccessTokenValue,
entity::setAccessTokenIssuedAt,
entity::setAccessTokenExpiresAt,
entity::setAccessTokenMetadata
);
if (accessToken != null && accessToken.getToken().getScopes() != null) {
entity.setAccessTokenScopes(StringUtils.collectionToDelimitedString(accessToken.getToken().getScopes(), ","));
}

OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken =
authorization.getToken(OAuth2RefreshToken.class);
setTokenValues(
refreshToken,
entity::setRefreshTokenValue,
entity::setRefreshTokenIssuedAt,
entity::setRefreshTokenExpiresAt,
entity::setRefreshTokenMetadata
);

OAuth2Authorization.Token<OidcIdToken> oidcIdToken =
authorization.getToken(OidcIdToken.class);
setTokenValues(
oidcIdToken,
entity::setOidcIdTokenValue,
entity::setOidcIdTokenIssuedAt,
entity::setOidcIdTokenExpiresAt,
entity::setOidcIdTokenMetadata
);
if (oidcIdToken != null) {
entity.setOidcIdTokenClaims(writeMap(oidcIdToken.getClaims()));
}

return entity;
}

private void setTokenValues(
OAuth2Authorization.Token<?> token,
Consumer<String> tokenValueConsumer,
Consumer<Instant> issuedAtConsumer,
Consumer<Instant> expiresAtConsumer,
Consumer<String> metadataConsumer) {
if (token != null) {
OAuth2Token oAuth2Token = token.getToken();
tokenValueConsumer.accept(oAuth2Token.getTokenValue());
issuedAtConsumer.accept(oAuth2Token.getIssuedAt());
expiresAtConsumer.accept(oAuth2Token.getExpiresAt());
metadataConsumer.accept(writeMap(token.getMetadata()));
}
}

private Map<String, Object> parseMap(String data) {
try {
return this.objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {
});
} catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
}

private String writeMap(Map<String, Object> metadata) {
try {
return this.objectMapper.writeValueAsString(metadata);
} catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
}

private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) {
if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.AUTHORIZATION_CODE;
} else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.CLIENT_CREDENTIALS;
} else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) {
return AuthorizationGrantType.REFRESH_TOKEN;
}
return new AuthorizationGrantType(authorizationGrantType); // Custom authorization grant type
}
}

授权同意服务

下面的清单显示了 ,它使用AuthorizationConsentRepository来持久保存 AuthorizationConsent,并映射到 OAuth2AuthorizationConsent 域对象和从OAuth2AuthorizationConsent域对象映射。​​JpaOAuth2AuthorizationConsentService​

​OAuth2AuthorizationConsentService​​实现

@Component
public class JpaOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService {
private final AuthorizationConsentRepository authorizationConsentRepository;
private final RegisteredClientRepository registeredClientRepository;

public JpaOAuth2AuthorizationConsentService(AuthorizationConsentRepository authorizationConsentRepository, RegisteredClientRepository registeredClientRepository) {
Assert.notNull(authorizationConsentRepository, "authorizationConsentRepository cannot be null");
Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
this.authorizationConsentRepository = authorizationConsentRepository;
this.registeredClientRepository = registeredClientRepository;
}

@Override
public void save(OAuth2AuthorizationConsent authorizationConsent) {
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
this.authorizationConsentRepository.save(toEntity(authorizationConsent));
}

@Override
public void remove(OAuth2AuthorizationConsent authorizationConsent) {
Assert.notNull(authorizationConsent, "authorizationConsent cannot be null");
this.authorizationConsentRepository.deleteByRegisteredClientIdAndPrincipalName(
authorizationConsent.getRegisteredClientId(), authorizationConsent.getPrincipalName());
}

@Override
public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) {
Assert.hasText(registeredClientId, "registeredClientId cannot be empty");
Assert.hasText(principalName, "principalName cannot be empty");
return this.authorizationConsentRepository.findByRegisteredClientIdAndPrincipalName(
registeredClientId, principalName).map(this::toObject).orElse(null);
}

private OAuth2AuthorizationConsent toObject(AuthorizationConsent authorizationConsent) {
String registeredClientId = authorizationConsent.getRegisteredClientId();
RegisteredClient registeredClient = this.registeredClientRepository.findById(registeredClientId);
if (registeredClient == null) {
throw new DataRetrievalFailureException(
"The RegisteredClient with id '" + registeredClientId + "' was not found in the RegisteredClientRepository.");
}

OAuth2AuthorizationConsent.Builder builder = OAuth2AuthorizationConsent.withId(
registeredClientId, authorizationConsent.getPrincipalName());
if (authorizationConsent.getAuthorities() != null) {
for (String authority : StringUtils.commaDelimitedListToSet(authorizationConsent.getAuthorities())) {
builder.authority(new SimpleGrantedAuthority(authority));
}
}

return builder.build();
}

private AuthorizationConsent toEntity(OAuth2AuthorizationConsent authorizationConsent) {
AuthorizationConsent entity = new AuthorizationConsent();
entity.setRegisteredClientId(authorizationConsent.getRegisteredClientId());
entity.setPrincipalName(authorizationConsent.getPrincipalName());

Set<String> authorities = new HashSet<>();
for (GrantedAuthority authority : authorizationConsent.getAuthorities()) {
authorities.add(authority.getAuthority());
}
entity.setAuthorities(StringUtils.collectionToCommaDelimitedString(authorities));

return entity;
}
}

标签:return,String,JPA,Spring,private,entity,varchar,服务器,NULL
From: https://blog.51cto.com/u_15326439/5914524

相关文章

  • 十四、Docker入门系列--Docker搭建部署SpringCloud微服务项目Demo
    十四、Docker入门系列--Docker搭建部署SpringCloud微服务项目Demo系列文章地址:一、Docker入门系列--Docker简介二、Docker入门系列--Docker安装三、Docker入门系列--D......
  • SpringCloud该如何入门及相关组件介绍
    前言什么是微服务?什么是SpringCloud?那SpringBoot与SpringCloud的区别又是什么?这几个问题是java开发工程师从SpringBoot向SpringCloud升级的一定回有的疑惑。......
  • 使用Spring Cloud Stream 驱动 RabbitMQ 代码示例
    1、SpringCloudStream官方文档官方配置文档参考:SpringCloudStreamReferenceDocumentationSpringCloudStreamRabbitMQBinderReferenceGuide说明:在网上查......
  • Spring Cloud - Feign
    JAVA项目中如何实现接口调用?1)HttpclientHttpClient是ApacheJakartaCommon下的子项目,用来提供高效的、最新的、功能丰富的支持Http协议的客户端编程工具包,并且它......
  • 免费云服务器
    优豆云https://www.udouyun.com高防云服务器最低100,高防物理机最低399免费云服务器,虚拟主机操作方便值得拥有注册链接:https://www.udouyun.com/register/?Laiyua......
  • SpringCloud-负载均衡和通信(Ribbon、Feign)
    1.Ribbon:负载均衡(基于客户端)1.1负载均衡以及RibbonRibbon是什么?SpringCloudRibbon是基于NetflixRibbon实现的一套客户端负载均衡的工具。简单的说,Ribbon是......
  • SpringCloud-Eureka服务注册中心
    1什么是EurekaNetflix在涉及Eureka时,遵循的就是API原则.Eureka是Netflix的有个子模块,也是核心模块之一。Eureka是基于REST的服务,用于定位服务,以实现云端中间件层服务发......
  • SpringCloud-入门
    1、学习前言1.2文章大纲SpringCloud五大组件服务注册与发现——NetflixEureka负载均衡:客户端负载均衡——NetflixRibbon服务端负载均衡:——Feign(其也是依......
  • SpringBoot构建RESTful风格应用
    SpringBoot构建RESTful风格应用1.Web开发的两种模式:前后端不分离:以前没有移动互联网时,我们做的大部分应用都是前后端不分的,比如jsp,或者thymeleaf等后端分离模板,在这种架......
  • 通过navicat 远程连接腾讯云服务器
    首先开放3306端口  再去mysql数据库下的user表中改权限,让被访问的user的host改为% 用腾讯云的连接,主机改成服务器的ip,用户名保持两方数据库一样   运行s......