Tomcat/服务器重启后spring + oauth2/api/oauth/token为“未授权" [英] spring + oauth2 /api/oauth/token is `Unauthorized` after Tomcat/server is restart
问题描述
我正在使用 spring-security-5
、spring-boot 2.0.5
和 oauth2
.我已经通过在线参考进行了检查和测试.
喜欢:
然后我重新启动服务器(Tomcat),我再次请求该 URL,我得到响应为
所以我的问题是,客户端应用程序如何在 Tomcat
或 spring-boot
应用程序重启后再次获得 access_token
?
一件事对于这种情况,如果我删除了数据库中OAUTH_CLIENT_DETAILS
表的记录,再次请求就可以了.我也再次获得access_token
.
更新
请不要错过理解响应 json
格式,我用自定义对象包装的每个响应,如下所示.
<代码>{"status": "SUCCESS", <-- 这是我的习惯数据":{"timestamp": "2018-12-18T07:17:00.776+0000", <-- 来自 oauth2 的实际响应"status": 401, <-- 来自 oauth2 的实际响应"error": "Unauthorized", <-- 来自 oauth2 的实际响应"message": "Unauthorized", <-- 来自 oauth2 的实际响应"path": "/api/oauth/token" <-- 来自 oauth2 的实际响应}}
更新 2
我使用JDBCTokenStore
,所有oauth
信息都保存在数据库中
package com.mutu.spring.rest.oauth2;导入 javax.sql.DataSource;导入 org.springframework.beans.factory.annotation.Autowired;导入 org.springframework.context.annotation.Bean;导入 org.springframework.context.annotation.Configuration;导入 org.springframework.security.authentication.AuthenticationManager;导入 org.springframework.security.core.userdetails.UserDetailsService;导入 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;导入 org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;导入 org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;导入 org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;导入 org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;导入 org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;导入 org.springframework.security.oauth2.provider.token.TokenStore;导入 org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;@配置@EnableAuthorizationServer公共类 AuthorizationServerConfig 扩展 AuthorizationServerConfigurerAdapter {static final String CLIEN_ID = "zto-api-client";//static final String CLIENT_SECRET = "zto-api-client";static final String CLIENT_SECRET = "$2a$04$HvD/aIuuta3B5DjXXzL08OSIcYEoFsAYK9Ys4fKpMNHTODZm.mzsq";静态最终字符串 GRANT_TYPE_PASSWORD = "密码";静态最终字符串 AUTHORIZATION_CODE = "authorization_code";静态最终字符串REFRESH_TOKEN = "refresh_token";静态最终字符串 IMPLICIT = "隐式";静态最终字符串SCOPE_READ =读取";静态最终字符串SCOPE_WRITE =写";静态最终字符串 TRUST = "信任";静态最终 int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60;静态最终 int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60;@自动连线私有 AuthenticationManager authenticationManager;@豆公共 BCryptPasswordEncoder passwordEncoder() {返回新的 BCryptPasswordEncoder();}@自动连线私有数据源数据源;@豆公共令牌商店令牌商店(){返回新的 JdbcTokenStore(dataSource);}@覆盖public void configure(AuthorizationServerSecurityConfigurer oauthServer) 抛出异常 {oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}@覆盖公共无效配置(ClientDetailsServiceConfigurer配置器)抛出异常{配置器.jdbc(数据源).withClient(CLIEN_ID).secret("{bcrypt}" + CLIENT_SECRET).authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)//.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT").scopes(SCOPE_READ, SCOPE_WRITE, TRUST).accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);}@覆盖public void configure(AuthorizationServerEndpointsConfigurer endpoints) 抛出异常 {endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);}}
在我的问题中,即使我使用了 JdbcTokenStore
,它在重启服务器后仍然得到 Unauthorized
响应.
现在,我得到了使用 JwtTokenStore
的问题的解决方案.它是无状态
.我只需要修改我的 AuthorizationServerConfig
类,如下所示.我的数据库中现在不需要任何 oauth
相关表.
import org.springframework.beans.factory.annotation.Autowired;导入 org.springframework.context.annotation.Bean;导入 org.springframework.context.annotation.Configuration;导入 org.springframework.security.authentication.AuthenticationManager;导入 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;导入 org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;导入 org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;导入 org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;导入 org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;导入 org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;导入 org.springframework.security.oauth2.provider.token.TokenStore;导入 org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;导入 org.springframework.security.oauth2.provider.token.store.JwtTokenStore;@配置@EnableAuthorizationServer公共类 AuthorizationServerConfig 扩展 AuthorizationServerConfigurerAdapter {static final String CLIEN_ID = "zto-api-client";//static final String CLIENT_SECRET = "zto-api-client";static final String CLIENT_SECRET = "$2a$04$HvD/aIuuta3B5DjXXzL08OSIcYEoFsAYK9Ys4fKpMNHTODZm.mzsq";静态最终字符串 GRANT_TYPE_PASSWORD = "密码";静态最终字符串 AUTHORIZATION_CODE = "authorization_code";静态最终字符串REFRESH_TOKEN = "refresh_token";静态最终字符串 IMPLICIT = "隐式";静态最终字符串SCOPE_READ =读取";静态最终字符串SCOPE_WRITE =写";静态最终字符串 TRUST = "信任";静态最终 int ACCESS_TOKEN_VALIDITY_SECONDS = 5*60;静态最终 int FREFRESH_TOKEN_VALIDITY_SECONDS = 5*60;@自动连线私有 AuthenticationManager authenticationManager;@豆公共 BCryptPasswordEncoder passwordEncoder() {返回新的 BCryptPasswordEncoder();}//替换@豆公共 JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter 转换器 = new JwtAccessTokenConverter();Converter.setSigningKey("as-you-like-your-key");返回转换器;}@豆公共令牌商店令牌商店(){返回新的 JwtTokenStore(accessTokenConverter());//替换}@覆盖public void configure(AuthorizationServerSecurityConfigurer oauthServer) 抛出异常 {oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}@覆盖公共无效配置(ClientDetailsServiceConfigurer配置器)抛出异常{配置器.inMemory()//替换.withClient(CLIEN_ID).secret("{bcrypt}" + CLIENT_SECRET).authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT).scopes(SCOPE_READ, SCOPE_WRITE, TRUST).accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);}@覆盖public void configure(AuthorizationServerEndpointsConfigurer endpoints) 抛出异常 {endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());//替换}}
I am using spring-security-5
, spring-boot 2.0.5
and oauth2
. I have checked and test by online reference.
Like :
Spring Security and OAuth2 to protect REST API endpoints
Spring Boot 2 Applications and OAuth 2
Everything is fine in my project.
When I request this URL , http://localhost:8080/api/oauth/token
, I get response as
And I restart the server(Tomcat), I request that URL again, I get response as
So my question is, how the client-app can get access_token
again after Tomcat
or spring-boot
application is restart?
One thing
For that kind of situation, if I delete the record of OAUTH_CLIENT_DETAILS
table in database, It is OK to request again. I also get access_token
again.
Update
Please don't miss understanding response json
format, every response I wrap by custom object like as below.
{
"status": "SUCCESS", <-- here my custom
"data": {
"timestamp": "2018-12-18T07:17:00.776+0000", <-- actual response from oauth2
"status": 401, <-- actual response from oauth2
"error": "Unauthorized", <-- actual response from oauth2
"message": "Unauthorized", <-- actual response from oauth2
"path": "/api/oauth/token" <-- actual response from oauth2
}
}
Update 2
I use JDBCTokenStore
, all of oauth
information keep in database
package com.mutu.spring.rest.oauth2;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
static final String CLIEN_ID = "zto-api-client";
// static final String CLIENT_SECRET = "zto-api-client";
static final String CLIENT_SECRET = "$2a$04$HvD/aIuuta3B5DjXXzL08OSIcYEoFsAYK9Ys4fKpMNHTODZm.mzsq";
static final String GRANT_TYPE_PASSWORD = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60;
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.jdbc(dataSource)
.withClient(CLIEN_ID)
.secret("{bcrypt}" + CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT )
// .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
}
In my question, even I use JdbcTokenStore
, it is still getting Unauthorized
response after restart the sever.
Now, I get a solution for my issue which is using JwtTokenStore
. It is stateless
. I just need to modify my AuthorizationServerConfig
class as below. I don't need any oauth
related table in my database now.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
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;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
static final String CLIEN_ID = "zto-api-client";
// static final String CLIENT_SECRET = "zto-api-client";
static final String CLIENT_SECRET = "$2a$04$HvD/aIuuta3B5DjXXzL08OSIcYEoFsAYK9Ys4fKpMNHTODZm.mzsq";
static final String GRANT_TYPE_PASSWORD = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 5*60;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 5*60;
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// replace
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("as-you-like-your-key");
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter()); // replace
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory() // replace
.withClient(CLIEN_ID)
.secret("{bcrypt}" + CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT )
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter());// replace
}
}
这篇关于Tomcat/服务器重启后spring + oauth2/api/oauth/token为“未授权"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!