Tomcat/服务器重启后spring + oauth2/api/oauth/token为“未授权" [英] spring + oauth2 /api/oauth/token is `Unauthorized` after Tomcat/server is restart

查看:59
本文介绍了Tomcat/服务器重启后spring + oauth2/api/oauth/token为“未授权"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 spring-security-5spring-boot 2.0.5oauth2.我已经通过在线参考进行了检查和测试.

喜欢:

然后我重新启动服务器(Tomcat),我再次请求该 URL,我得到响应为

所以我的问题是,客户端应用程序如何在 Tomcatspring-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.UserDetailsS​​ervice;导入 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;导入 org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsS​​erviceConfigurer;导入 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()");}@覆盖公共无效配置(ClientDetailsS​​erviceConfigurer配置器)抛出异常{配置器.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.ClientDetailsS​​erviceConfigurer;导入 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()");}@覆盖公共无效配置(ClientDetailsS​​erviceConfigurer配置器)抛出异常{配置器.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆