为什么 OAuth2 身份验证服务器 returns 401 错误与 jdbc 数据源?
Why does OAuth2 authentication server returns 401 error with jdbc datasource?
我正在使用 JWT 实现 OAUTH2 身份验证服务器。
如果我使用 inMemory () 令牌,我可以正常访问。
但是,如果我使用 jdbc(数据源),它总是 returns 错误 401。有人能帮忙吗?
我的 AuthorizationServerConfigurerAdapter
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager)
.tokenEnhancer(jwtAccessTokenConverter()).userDetailsService(userDetailsService)
.requestFactory(customOauth2RequestFactory.requestFactory());
}
我的tokenStore
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
还有我的 jwtAccessTokenConverter
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
var converteToken = new CustomToken();
converteToken.setKeyPair(new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "password".toCharArray())
.getKeyPair("jwt"));
return converteToken;
}
我的 CustomToken extends extends JwtAccessTokenConverter
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
var user = userRepository.findByLogin(authentication.getName());
Map<String, Object> additionalInformation = new HashMap<>() {{
put("idFuncionario", usuario.getIdFuncionario());
put("idEmpresa", usuario.getIdEmpresa());
put("perfis", usuario.descricaoPerfil());
put("login", usuario.getLogin());
}};
var defaultOAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
defaultOAuth2AccessToken.setAdditionalInformation(additionalInformation);
return super.enhance(defaultOAuth2AccessToken, authentication);
}
现在,我的 JDBC 在 AuthorizationServerConfigurerAdapter
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder());
}
我的 CustomFactory 扩展了 DefaultOAuth2RequestFactory
@Override
public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
if (requestParameters.get("grant_type").equals("refresh_token")) {
var authentication = tokenStore.readAuthenticationForRefreshToken(tokenStore.readRefreshToken(requestParameters
.get("refresh_token")));
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
authentication.getName(), null, userDetailsService.loadUserByUsername(authentication.getName())
.getAuthorities()));
}
return super.createTokenRequest(requestParameters, authenticatedClient);
}
还有我的 JWT 实体
@Entity
@Table(name = "oauth_client_details")
public class OAuthClientDetails extends AbstractEntity {
private String clientId;
private String clientSecret;
private String resourceIds;
private String scope;
private String authorizedGrantTypes;
private String webServerRedirectUri;
private String authorities;
private Integer accessTokenValidity;
private Integer refreshTokenValidity;
private String additionalInformation;
private String autoapprove;
contructor / geters / seters
我的解决方案:
我在扩展 AuthorizationServerConfigurerAdapter
的 class 中创建了这个方法
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientService);
}
而这项服务:
@Service
public class ClientService implements ClientDetailsService {
@Autowired
private ClienteRepository clienteRepository;
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
var cliente = clienteRepository.findById(clientId);
var clienteDetail = new ClienteDetalhes(
cliente.get().getClientId(),
String.join(",", cliente.get().getResourceIds()),
cliente.get().getClientSecret(),
String.join(",", cliente.get().getScope()),
String.join(",", cliente.get().getAuthorizedGrantTypes()),
String.join(",", cliente.get().getRegisteredRedirectUri()),
null,
cliente.get().getAccessTokenValiditySeconds(),
cliente.get().getRefreshTokenValiditySeconds(),
cliente.get().getAutoApproveScope(),
null);
return clienteDetail;
}
}
还有这个实体
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(schema = "cliente")
public class ClienteDetalhes implements Serializable, ClientDetails {
private static final ObjectMapper mapper = new ObjectMapper();
@Id
@Column(nullable = false, unique = true)
private String clientId;
private String resourceIds;
private String clientSecret;
private String scope;
@Column(nullable = false)
private String authorizedGrantTypes;
private String registeredRedirectUri;
private String authorities;
@Column(nullable = false)
private Integer accessTokenValiditySeconds;
@Column(nullable = false)
private Integer refreshTokenValiditySeconds;
private String autoApproveScope;
private String additionalInformation;
@Override
public boolean isSecretRequired() {
return !StringUtils.isEmpty(this.clientSecret);
}
@Override
public boolean isAutoApprove(String scope) {
return false;
}
@Override
public Map<String, Object> getAdditionalInformation() {
try {
return mapper.readValue(this.additionalInformation, Map.class);
} catch (IOException e) {
return new HashMap<>();
}
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
Set<String> set = StringUtils.commaDelimitedListToSet(this.authorities);
Set<GrantedAuthority> result = new HashSet<>();
set.forEach(authority -> result.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return authority;
}
}));
return result;
}
@Override
public Set<String> getRegisteredRedirectUri() {
return StringUtils.commaDelimitedListToSet(this.registeredRedirectUri);
}
@Override
public Set<String> getAuthorizedGrantTypes() {
return StringUtils.commaDelimitedListToSet(this.authorizedGrantTypes);
}
@Override
public boolean isScoped() {
return this.getScope().size() > 0;
}
@Override
public Set<String> getScope() {
return StringUtils.commaDelimitedListToSet(this.scope);
}
@Override
public Set<String> getResourceIds() {
if (StringUtils.isEmpty(this.resourceIds)) {
return new HashSet<>();
} else {
return StringUtils.commaDelimitedListToSet(this.resourceIds);
}
}
}
现在一切正常!
我正在使用 JWT 实现 OAUTH2 身份验证服务器。 如果我使用 inMemory () 令牌,我可以正常访问。 但是,如果我使用 jdbc(数据源),它总是 returns 错误 401。有人能帮忙吗?
我的 AuthorizationServerConfigurerAdapter
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager)
.tokenEnhancer(jwtAccessTokenConverter()).userDetailsService(userDetailsService)
.requestFactory(customOauth2RequestFactory.requestFactory());
}
我的tokenStore
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
还有我的 jwtAccessTokenConverter
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
var converteToken = new CustomToken();
converteToken.setKeyPair(new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "password".toCharArray())
.getKeyPair("jwt"));
return converteToken;
}
我的 CustomToken extends extends JwtAccessTokenConverter
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
var user = userRepository.findByLogin(authentication.getName());
Map<String, Object> additionalInformation = new HashMap<>() {{
put("idFuncionario", usuario.getIdFuncionario());
put("idEmpresa", usuario.getIdEmpresa());
put("perfis", usuario.descricaoPerfil());
put("login", usuario.getLogin());
}};
var defaultOAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
defaultOAuth2AccessToken.setAdditionalInformation(additionalInformation);
return super.enhance(defaultOAuth2AccessToken, authentication);
}
现在,我的 JDBC 在 AuthorizationServerConfigurerAdapter
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder());
}
我的 CustomFactory 扩展了 DefaultOAuth2RequestFactory
@Override
public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
if (requestParameters.get("grant_type").equals("refresh_token")) {
var authentication = tokenStore.readAuthenticationForRefreshToken(tokenStore.readRefreshToken(requestParameters
.get("refresh_token")));
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
authentication.getName(), null, userDetailsService.loadUserByUsername(authentication.getName())
.getAuthorities()));
}
return super.createTokenRequest(requestParameters, authenticatedClient);
}
还有我的 JWT 实体
@Entity
@Table(name = "oauth_client_details")
public class OAuthClientDetails extends AbstractEntity {
private String clientId;
private String clientSecret;
private String resourceIds;
private String scope;
private String authorizedGrantTypes;
private String webServerRedirectUri;
private String authorities;
private Integer accessTokenValidity;
private Integer refreshTokenValidity;
private String additionalInformation;
private String autoapprove;
contructor / geters / seters
我的解决方案:
我在扩展 AuthorizationServerConfigurerAdapter
的 class 中创建了这个方法 @Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientService);
}
而这项服务:
@Service
public class ClientService implements ClientDetailsService {
@Autowired
private ClienteRepository clienteRepository;
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
var cliente = clienteRepository.findById(clientId);
var clienteDetail = new ClienteDetalhes(
cliente.get().getClientId(),
String.join(",", cliente.get().getResourceIds()),
cliente.get().getClientSecret(),
String.join(",", cliente.get().getScope()),
String.join(",", cliente.get().getAuthorizedGrantTypes()),
String.join(",", cliente.get().getRegisteredRedirectUri()),
null,
cliente.get().getAccessTokenValiditySeconds(),
cliente.get().getRefreshTokenValiditySeconds(),
cliente.get().getAutoApproveScope(),
null);
return clienteDetail;
}
}
还有这个实体
@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(schema = "cliente")
public class ClienteDetalhes implements Serializable, ClientDetails {
private static final ObjectMapper mapper = new ObjectMapper();
@Id
@Column(nullable = false, unique = true)
private String clientId;
private String resourceIds;
private String clientSecret;
private String scope;
@Column(nullable = false)
private String authorizedGrantTypes;
private String registeredRedirectUri;
private String authorities;
@Column(nullable = false)
private Integer accessTokenValiditySeconds;
@Column(nullable = false)
private Integer refreshTokenValiditySeconds;
private String autoApproveScope;
private String additionalInformation;
@Override
public boolean isSecretRequired() {
return !StringUtils.isEmpty(this.clientSecret);
}
@Override
public boolean isAutoApprove(String scope) {
return false;
}
@Override
public Map<String, Object> getAdditionalInformation() {
try {
return mapper.readValue(this.additionalInformation, Map.class);
} catch (IOException e) {
return new HashMap<>();
}
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
Set<String> set = StringUtils.commaDelimitedListToSet(this.authorities);
Set<GrantedAuthority> result = new HashSet<>();
set.forEach(authority -> result.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return authority;
}
}));
return result;
}
@Override
public Set<String> getRegisteredRedirectUri() {
return StringUtils.commaDelimitedListToSet(this.registeredRedirectUri);
}
@Override
public Set<String> getAuthorizedGrantTypes() {
return StringUtils.commaDelimitedListToSet(this.authorizedGrantTypes);
}
@Override
public boolean isScoped() {
return this.getScope().size() > 0;
}
@Override
public Set<String> getScope() {
return StringUtils.commaDelimitedListToSet(this.scope);
}
@Override
public Set<String> getResourceIds() {
if (StringUtils.isEmpty(this.resourceIds)) {
return new HashSet<>();
} else {
return StringUtils.commaDelimitedListToSet(this.resourceIds);
}
}
}
现在一切正常!