Spring oauth2刷新令牌-无法将访问令牌转换为JSON
我试图在SpringOAuth应用程序中使用刷新令牌,但没有成功。系统将在密码授予时发出刷新令牌:Spring oauth2刷新令牌-无法将访问令牌转换为JSON,spring,oauth-2.0,spring-security-oauth2,Spring,Oauth 2.0,Spring Security Oauth2,我试图在SpringOAuth应用程序中使用刷新令牌,但没有成功。系统将在密码授予时发出刷新令牌: { "access_token": "xxxxx", "token_type": "bearer", "refresh_token": "xxxxxx", "expires_in": 21599, "scope": "read write" } 但尝试使用刷新令牌会导致以下错误: curl-u acme-d“授权类型=刷新令牌&刷新令牌=xxxxxx” 我的身份验证服务器
{
"access_token": "xxxxx",
"token_type": "bearer",
"refresh_token": "xxxxxx",
"expires_in": 21599,
"scope": "read write"
}
但尝试使用刷新令牌会导致以下错误:
curl-u acme-d“授权类型=刷新令牌&刷新令牌=xxxxxx”
我的身份验证服务器配置如下:
@Controller
@SessionAttributes("authorizationRequest")
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@EnableResourceServer
@ImportResource("classpath:/spring/application-context.xml")
@Configuration
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
@RequestMapping("/user")
@ResponseBody
public Principal user(Principal user) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println(auth.toString());
return user;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/oauth/confirm_access").setViewName("authorize");
}
@Configuration
@Order(-20)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// @formatter:off
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated();
// @formatter:on
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
public static class JwtConfiguration {
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "foobar".toCharArray())
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
@Bean
public JwtTokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
}
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter implements
EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private JwtTokenStore jwtTokenStore;
@Autowired
@Qualifier("myUserDetailsService")
private UserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(jwtTokenStore);
tokenServices.setAuthenticationManager(authenticationManager);
tokenServices.setTokenEnhancer(tokenEnhancer());
return tokenServices;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
// The order is important here - the custom enhancer must come before the jwtAccessTokenConverter.
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter));
endpoints
.authenticationManager(authenticationManager)
.tokenEnhancer(tokenEnhancerChain)
.tokenStore(jwtTokenStore)
.userDetailsService(userDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
/*.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.autoApprove(true)
.authorities(ClientAuthoritiesConstants.CLIENT)
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer
.class, 1800));*/
}
}
/**
* Configures the global LDAP authentication
*/
@Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter implements EnvironmentAware {
private static final String ENV_LDAP = "authentication.ldap.";
private static final String PROP_SEARCH_BASE = "userSearchBase";
private static final String PROP_SEARCH_FILTER = "userSearchFilter";
private static final String PROP_GROUP_SEARCH_FILTER = "groupSearchFilter";
private static final String PROP_LDAP_URL = "url";
private static final String PROP_LDAP_USER = "userDn";
private static final String PROP_LDAP_PASS = "password";
private RelaxedPropertyResolver propertyResolver;
/**
* Maps the LDAP user to the Principle that we'll be using in the app
*/
public UserDetailsContextMapper userDetailsContextMapper() {
return new UserDetailsContextMapper() {
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) {
// Get the common name of the user
String commonName = ctx.getStringAttribute("cn");
// Get the users email address
String email = ctx.getStringAttribute("mail");
// Get the domino user UNID
String uId = ctx.getStringAttribute("uid");
return new CustomUserDetails(email, "", commonName, authorities);
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
throw new IllegalStateException("Only retrieving data from LDAP is currently supported");
}
};
}
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_LDAP);
}
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userSearchBase(propertyResolver.getProperty(PROP_SEARCH_BASE))
.groupSearchBase(propertyResolver.getProperty(PROP_SEARCH_BASE))
.userSearchFilter(propertyResolver.getProperty(PROP_SEARCH_FILTER))
.groupSearchFilter(propertyResolver.getProperty(PROP_GROUP_SEARCH_FILTER))
.userDetailsContextMapper(userDetailsContextMapper())
.contextSource()
.url(propertyResolver.getProperty(PROP_LDAP_URL))
.managerDn(propertyResolver.getProperty(PROP_LDAP_USER))
.managerPassword(propertyResolver.getProperty(PROP_LDAP_PASS));
}
}
}
@控制器
@会期贡献(“授权请求”)
@EnableGlobalMethodSecurity(securedEnabled=true,Prespenabled=true)
@EnableResourceServer
@ImportResource(“classpath:/spring/application context.xml”)
@配置
公共类应用程序配置扩展了WebMVCConfigureAdapter{
@请求映射(“/user”)
@应答器
公共主要用户(主要用户){
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
System.out.println(auth.toString());
返回用户;
}
@凌驾
public void addViewController(ViewControllerRegistry注册表){
registry.addViewController(“/login”).setViewName(“login”);
registry.addViewController(“/oauth/confirm_access”).setViewName(“authorize”);
}
@配置
@订单(-20)
受保护的静态类LoginConfig扩展了WebSecurity配置适配器{
@自动连线
私人AuthenticationManager AuthenticationManager;
@凌驾
受保护的无效配置(HttpSecurity http)引发异常{
http.csrf().disable();
//@formatter:off
http
.formLogin().loginPage(“/login”).permitAll()
.及()
.requestMatchers().antMatchers(“/login”、“/oauth/authorize”、“/oauth/confirm\u access”)
.及()
.authorizeRequests().anyRequest().authorized();
//@formatter:on
}
@豆子
@凌驾
公共AuthenticationManager authenticationManagerBean()引发异常{
返回super.authenticationManagerBean();
}
}
@配置
公共静态类JWT配置{
@豆子
公共JwtAccessTokenConverter JwtAccessTokenConverter(){
JwtAccessTokenConverter=新的JwtAccessTokenConverter();
KeyPair KeyPair=newkeystorekeyfactory(新类路径资源(“keystore.jks”),“foobar.toCharArray())
.getKeyPair(“测试”);
转换器。设置密钥对(密钥对);
回流转换器;
}
@豆子
公共JwtTokenStore JwtTokenStore(){
返回新的JwtTokenStore(jwtAccessTokenConverter());
}
}
@配置
@EnableAuthorizationServer
受保护的静态类OAuth2AuthorizationConfig扩展了AuthorizationServerConfigurerAdapter实现
环保意识{
私有静态最终字符串ENV_OAUTH=“authentication.OAUTH。”;
私有静态最终字符串PROP_CLIENTID=“CLIENTID”;
私有静态最终字符串PROP_SECRET=“SECRET”;
私有静态最终字符串PROP_TOKEN_VALIDITY_SECONDS=“tokenvalidityinsonds”;
私人休闲房地产开发商房地产开发商;
@自动连线
私人AuthenticationManager AuthenticationManager;
@自动连线
私有JwtAccessTokenConverter JwtAccessTokenConverter;
@自动连线
私人JwtTokenStore JwtTokenStore;
@自动连线
@限定符(“myUserDetailsService”)
私有用户详细信息服务用户详细信息服务;
@自动连线
私有数据源;
@凌驾
公共环境(环境){
this.propertyResolver=新的RelaxedPropertyResolver(环境,环境);
}
@豆子
公共令牌增强器令牌增强器(){
返回新的CustomTokenEnhancer();
}
@豆子
@初级的
公共DefaultTokenServices令牌服务(){
DefaultTokenServices tokenServices=新的DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
setTokenStore(jwtTokenStore);
setAuthenticationManager(authenticationManager);
setTokenEnhancer(tokenEnhancer());
退货服务;
}
@凌驾
public void configure(AuthorizationServerEndpointsConfigurer端点)引发异常{
TokenEnhancerCain TokenEnhancerCain=新的TokenEnhancerCain();
//这里的顺序很重要-自定义增强器必须位于jwtAccessTokenConverter之前。
tokenEnhancerCain.setTokenEnhancers(Arrays.asList(tokenEnhancer(),jwtAccessTokenConverter));
端点
.authenticationManager(authenticationManager)
.tokenEnhancer(TokenEnhancerCain)
.tokenStore(jwtTokenStore)
.userDetailsService(userDetailsService);
}
@凌驾
public void配置(AuthorizationServerSecurityConfigure oauthServer)
抛出异常{
oauthServer.tokenKeyAccess(“permitAll()”).checkTokenAccess(“isAuthenticated()”);
}
@凌驾
公共无效配置(ClientDetailsServiceConfigurer客户端)引发异常{
jdbc(数据源);
/*.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.作用域(“读”、“写”)
.autoApprove(true)
.authorities(ClientAuthoritiesConstants.CLIENT)
.authorizedGrantTypes(“授权码”、“刷新令牌”、“密码”)
.secret(propertyResolver.getProperty(PROP_secret))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS,整数
.类,1800)*/
}
}
/**
*配置
@Controller
@SessionAttributes("authorizationRequest")
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@EnableResourceServer
@ImportResource("classpath:/spring/application-context.xml")
@Configuration
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
@RequestMapping("/user")
@ResponseBody
public Principal user(Principal user) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println(auth.toString());
return user;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/oauth/confirm_access").setViewName("authorize");
}
@Configuration
@Order(-20)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// @formatter:off
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated();
// @formatter:on
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
public static class JwtConfiguration {
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "foobar".toCharArray())
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
@Bean
public JwtTokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
}
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter implements
EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private JwtTokenStore jwtTokenStore;
@Autowired
@Qualifier("myUserDetailsService")
private UserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(jwtTokenStore);
tokenServices.setAuthenticationManager(authenticationManager);
tokenServices.setTokenEnhancer(tokenEnhancer());
return tokenServices;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
// The order is important here - the custom enhancer must come before the jwtAccessTokenConverter.
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter));
endpoints
.authenticationManager(authenticationManager)
.tokenEnhancer(tokenEnhancerChain)
.tokenStore(jwtTokenStore)
.userDetailsService(userDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
/*.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.autoApprove(true)
.authorities(ClientAuthoritiesConstants.CLIENT)
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer
.class, 1800));*/
}
}
/**
* Configures the global LDAP authentication
*/
@Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter implements EnvironmentAware {
private static final String ENV_LDAP = "authentication.ldap.";
private static final String PROP_SEARCH_BASE = "userSearchBase";
private static final String PROP_SEARCH_FILTER = "userSearchFilter";
private static final String PROP_GROUP_SEARCH_FILTER = "groupSearchFilter";
private static final String PROP_LDAP_URL = "url";
private static final String PROP_LDAP_USER = "userDn";
private static final String PROP_LDAP_PASS = "password";
private RelaxedPropertyResolver propertyResolver;
/**
* Maps the LDAP user to the Principle that we'll be using in the app
*/
public UserDetailsContextMapper userDetailsContextMapper() {
return new UserDetailsContextMapper() {
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) {
// Get the common name of the user
String commonName = ctx.getStringAttribute("cn");
// Get the users email address
String email = ctx.getStringAttribute("mail");
// Get the domino user UNID
String uId = ctx.getStringAttribute("uid");
return new CustomUserDetails(email, "", commonName, authorities);
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
throw new IllegalStateException("Only retrieving data from LDAP is currently supported");
}
};
}
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_LDAP);
}
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userSearchBase(propertyResolver.getProperty(PROP_SEARCH_BASE))
.groupSearchBase(propertyResolver.getProperty(PROP_SEARCH_BASE))
.userSearchFilter(propertyResolver.getProperty(PROP_SEARCH_FILTER))
.groupSearchFilter(propertyResolver.getProperty(PROP_GROUP_SEARCH_FILTER))
.userDetailsContextMapper(userDetailsContextMapper())
.contextSource()
.url(propertyResolver.getProperty(PROP_LDAP_URL))
.managerDn(propertyResolver.getProperty(PROP_LDAP_USER))
.managerPassword(propertyResolver.getProperty(PROP_LDAP_PASS));
}
}
}
JwtAccessTokenConverter
...protected Map<String, Object> decode(String token) {
try {
Jwt jwt = JwtHelper.decodeAndVerify(token, verifier);
private JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new CustomTokenEnhancer();
jwtAccessTokenConverter.setSigningKey(jwtSigningKey);
jwtAccessTokenConverter.setVerifier(new RsaVerifier(jwtPublicKey));
log.info("Set JWT signing key to: {}", jwtAccessTokenConverter.getKey());
return jwtAccessTokenConverter;
}
<!-- Access token converter -->
<bean id="jwtAccessTokenConverter"
class="org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter">
<property name="signingKey" value="${security.jwt.signing-key}"/>
</bean>
<!-- Token store -->
<bean id="jwtTokenStore"
class="org.springframework.security.oauth2.provider.token.store.JwtTokenStore">
<constructor-arg name="jwtTokenEnhancer" ref="jwtAccessTokenConverter"/>
</bean>
<!-- Creates token store services provider -->
<bean id="tokenServiceProvider"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore"
ref="jwtTokenStore"/>
<!--This must be set according to z docs -->
<property name="tokenEnhancer"
ref="jwtAccessTokenConverter"/>
<property name="supportRefreshToken"
value="true"/>
<property name="accessTokenValiditySeconds"
value="${security.jwt.access-token-validity-seconds}"/>
<property name="refreshTokenValiditySeconds"
value="${security.jwt.refresh-token-validity-seconds}"/>
</bean>