gpt4 book ai didi

Spring Boot 2 和 OAuth2/JWT 配置

转载 作者:IT老高 更新时间:2023-10-28 13:47:27 26 4
gpt4 key购买 nike

我正在尝试将我的 Spring Boot 1.5 应用程序移植到 Spring Boot 2

现在我无法获取 OAuth2 访问 token 。

这是我在 Spring Boot 1.5 中成功使用的代码:

public static String loginAndGetAccessToken(String username, String password, int port) {

ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();
resourceDetails.setUsername(username);
resourceDetails.setPassword(password);
resourceDetails.setAccessTokenUri(String.format("http://localhost:%d/api/oauth/token", port));
resourceDetails.setClientId("clientapp");
resourceDetails.setClientSecret("123456");
resourceDetails.setGrantType("password");
resourceDetails.setScope(Arrays.asList("read", "write"));

DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));

return restTemplate.getAccessToken().toString();
}

它失败了,但有以下异常:

java.lang.IllegalStateException: An OAuth 2 access token must be obtained or an exception thrown.
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:124)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)

看起来 http://localhost:%d/api/oauth/token 端点现在是安全的,无法访问

这是我的配置:

OAuth2ServerConfig

@Configuration
public class OAuth2ServerConfig {

public static final String RESOURCE_ID = "restservice";
public static final String EXAMPLE_CLIENT_ID = "example_client_id";

@Value("${jwt.access.token.converter.signing.key}")
private String jwtAccessTokenConverterSigningKey;

@Value("${jwt.access.token.validity.seconds}")
private int accessTokenValiditySeconds;

@Autowired
private UserDetailsService userDetailsService;

@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
return tokenServices;
}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new UserAwareAccessTokenConverter();

converter.setSigningKey(jwtAccessTokenConverterSigningKey);

DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
userTokenConverter.setUserDetailsService(userDetailsService);
accessTokenConverter.setUserTokenConverter(userTokenConverter);

converter.setAccessTokenConverter(accessTokenConverter);

return converter;
}

@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

@Value("${jwt.access.token.validity.seconds}")
private int accessTokenValiditySeconds;

@Autowired
private TokenStore tokenStore;

@Autowired
private TokenEnhancer tokenEnhancer;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// @formatter:off
endpoints
.tokenStore(tokenStore)
.tokenEnhancer(tokenEnhancer)
.authenticationManager(this.authenticationManager);
// @formatter:on
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// @formatter:off
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password","refresh_token")
.authorities("ROLE_CLIENT")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("123456")
.and()
.withClient(EXAMPLE_CLIENT_ID)
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.autoApprove(true)
.and()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(accessTokenValiditySeconds);
// @formatter:on
}

}

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

@Autowired
private ResourceServerTokenServices tokenService;

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
// @formatter:off
resources
.resourceId(RESOURCE_ID)
.tokenServices(tokenService);
// @formatter:on
}

@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.antMatcher("/v1.0/**").authorizeRequests()
.antMatchers("/v1.0/search/**").permitAll()
.antMatchers("/v1.0/users/**").permitAll()
.antMatchers("/v1.0/decisions/**").permitAll()
.antMatchers("/v1.0/votes/**").permitAll()
.antMatchers("/v1.0/likes/**").permitAll()
.antMatchers("/v1.0/likeables/**").permitAll()
.antMatchers("/v1.0/flags/**").permitAll()
.antMatchers("/v1.0/flagtypes/**").permitAll()
.antMatchers("/v1.0/flaggables/**").permitAll()
.antMatchers("/v1.0/comments/**").permitAll()
.antMatchers("/v1.0/commentables/**").permitAll()
.antMatchers("/v1.0/subscribables/**").permitAll()
.antMatchers("/v1.0/favoritables/**").permitAll()
.antMatchers("/v1.0/import/**").permitAll()
.antMatchers("/v1.0/tags/**").permitAll()
.antMatchers("/v1.0/medias/**").permitAll()
.antMatchers("/swagger**").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(STATELESS);
// @formatter:on
}

}

}

WebMvcConfig

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login").setViewName("login");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");

registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");

registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}

}

WebSecurityConfig

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Value("${logout.success.url}")
private String logoutSuccessUrl;

@Override
protected void configure(HttpSecurity http) throws Exception {

// @formatter:off
http
.cors()
.and()
.csrf().ignoringAntMatchers("/v1.0/**", "/logout")
.and()
.authorizeRequests()

.antMatchers("/oauth/authorize").authenticated()
//Anyone can access the urls
.antMatchers("/images/**").permitAll()
.antMatchers("/signin/**").permitAll()
.antMatchers("/v1.0/**").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority(Permission.READ_ACTUATOR_DATA)
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl(logoutSuccessUrl)
.permitAll();
// @formatter:on
}

/**
* Configures the authentication manager bean which processes authentication requests.
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}

}

为了让它与 Spring Boot 2 一起工作,应该进行哪些更改?

最佳答案

OAuth2ServerConfig

import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import com.decisionwanted.api.security.authentication.UserAwareAccessTokenConverter;
import com.decisionwanted.domain.service.user.social.UserDetailsService;

@Configuration
public class OAuth2ServerConfig {

public static final String RESOURCE_ID = "restservice";
public static final String CLIENT_ID = "client_id";

@Value("${jwt.access.token.converter.signing.key}")
private String jwtAccessTokenConverterSigningKey;

@Value("${jwt.access.token.validity.seconds}")
private int accessTokenValiditySeconds;

@Autowired
private UserDetailsService userDetailsService;

@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
return tokenServices;
}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new UserAwareAccessTokenConverter();

converter.setSigningKey(jwtAccessTokenConverterSigningKey);

DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
userTokenConverter.setUserDetailsService(userDetailsService);
accessTokenConverter.setUserTokenConverter(userTokenConverter);

converter.setAccessTokenConverter(accessTokenConverter);

return converter;
}

@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

@Value("${jwt.access.token.validity.seconds}")
private int accessTokenValiditySeconds;

@Autowired
private TokenStore tokenStore;

@Autowired
private TokenEnhancer tokenEnhancer;

private PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// @formatter:off
endpoints
.tokenStore(tokenStore)
.tokenEnhancer(tokenEnhancer)
.authenticationManager(this.authenticationManager);
// @formatter:on
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// @formatter:off
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password","refresh_token")
.authorities("ROLE_CLIENT")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret(passwordEncoder.encode("changeit"))
.and()
.withClient(CLIENT_ID)
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.autoApprove(true)
.and()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(accessTokenValiditySeconds);
// @formatter:on
}

}

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

@Autowired
private ResourceServerTokenServices tokenService;

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
// @formatter:off
resources
.resourceId(RESOURCE_ID)
.tokenServices(tokenService);
// @formatter:on
}

@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.antMatcher("/v1.0/**").authorizeRequests()
.antMatchers("/v1.0/search/**").permitAll()
.antMatchers("/v1.0/users/**").permitAll()
.antMatchers("/v1.0/decisiongroups/**").permitAll()
.antMatchers("/swagger**").permitAll()
.anyRequest().authenticated()
.and()
.cors()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(STATELESS);
// @formatter:on
}

}

}

WebMvcConfig

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login").setViewName("login");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");

registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");

registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}

}

WebSecurityConfig

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import com.decisionwanted.domain.model.neo4j.security.permission.Permission;
import com.decisionwanted.domain.service.user.social.UserDetailsService;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Value("${logout.success.url}")
private String logoutSuccessUrl;

PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

@Override
protected void configure(HttpSecurity http) throws Exception {

// @formatter:off
http
.cors()
.and()
.csrf().ignoringAntMatchers("/v1.0/**", "/logout")
.and()
.authorizeRequests()

.antMatchers("/oauth/authorize").authenticated()
//Anyone can access the urls
.antMatchers("/images/**").permitAll()
.antMatchers("/signin/**").permitAll()
.antMatchers("/v1.0/**").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority(Permission.READ_ACTUATOR_DATA)
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl(logoutSuccessUrl)
.permitAll();
// @formatter:on
}

/**
* Configures the authentication manager bean which processes authentication requests.
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}

}

SecurityTestUtils

import java.util.Arrays;

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;

public class SecurityTestUtils {

public static final String AUTH_HEADER_NAME = "Authorization";
public static final String AUTH_COOKIE_NAME = "AUTH-TOKEN";

public static String loginAndGetAccessToken(String username, String password, int port) {

ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();
resourceDetails.setUsername(username);
resourceDetails.setPassword(password);
resourceDetails.setAccessTokenUri(String.format("http://localhost:%d/api/oauth/token", port));
resourceDetails.setClientId("clientapp");
resourceDetails.setClientSecret("changeit");
resourceDetails.setGrantType("password");
resourceDetails.setScope(Arrays.asList("read", "write"));

DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));

return restTemplate.getAccessToken().toString();
}

}

关于Spring Boot 2 和 OAuth2/JWT 配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45391264/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com