spring - 如何在 Spring Security JDBC 中保留 oauth 访问 token ?

标签 spring spring-security oauth-2.0 spring-data-rest spring-security-oauth2

当用户登录时,我生成一个 token ,因此当用户想要访问 RESTapi 的信息时,他将不会再次登录,代码有效,但我遇到了问题。

spring 生成的 token 有效,但是当我重新编译我编写的代码时,该 token 不再起作用,我应该请求一个新 token 来使用“bearer $Token”,这是正常行为还是我应该在设置中修复某些内容?

例子 :
curl -u test: http://localhost:8080/oauth/token -d "grant_type=password&username=id&password=pass"{"access_token":"a46c3cf4-6777-4a61-9f71-268be047c383","token_type":"bearer","refresh_token":"8ef69c18-1a9e-47c0-ba80-b51a34144e9a","expires_in":603005,"scope":"read write trust"}
当我重新编译代码时:
curl -u test: http://localhost:8080/oauth/token -d "grant_type=password&username=id&password=pass"{"access_token":"1a69f140-47ac-4dde-9786-1d4f14f9a389","token_type":"bearer","refresh_token":"be99d434-54a0-4273-add8-cccad95caec3","expires_in":604799,"scope":"read write trust"}
这是我的代码:

import com.lms.entities.UsersEntity;
import com.lms.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.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.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@Configuration
@ComponentScan
@EnableAutoConfiguration
@RestController
class SpringBackendScoutApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBackendScoutApplication.class, args);
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                    .requestMatchers()
                    .antMatchers(
                            Constants.USERS, Constants.COMMENTS, Constants.FRIENDS_REQUEST,
                            Constants.MUSICS, Constants.PHOTOS, Constants.POSTS, Constants.VIDEOS,
                            Constants.PROFILE_PHOTOS, Constants.FRIENDS, "/"
                    ).and()
                    .authorizeRequests()
                    .anyRequest().access("#oauth2.hasScope('read')")
                    .and().logout();
            // @formatter:on
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId("sparklr");
        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(authenticationManager);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("test")
                    .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
                    .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
                    .scopes("read", "write", "trust")
                    .resourceIds("sparklr")
                    .accessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(7))

            ;
        }

    }

    @Configuration
    @EnableWebSecurity
    protected static class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        UserRepository userRepository;

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            for (UsersEntity user : userRepository.findAll())
                if (user.getUsername() != null && user.getPassword() != null)
                    auth.inMemoryAuthentication().withUser(user.getUsername()).password(user.getPassword()).roles("USER");
        }

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

    }

}

最佳答案

为了解决这个问题,你应该添加一个 token 存储来保存每次生成的 token :

protected static class ResourceServer extends ResourceServerConfigurerAdapter {

    @Value("${spring.datasource.driverClassName}")
    private String oauthClass;

    @Value("${spring.datasource.url}")
    private String oauthUrl;

    @Bean
    public TokenStore tokenStore() {
        DataSource tokenDataSource = DataSourceBuilder.create()
                        .driverClassName(oauthClass)
                        .username("root")
                        .password("")
                        .url(oauthUrl)
                        .build();
        return new JdbcTokenStore(tokenDataSource);
    }
}

@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    resources.resourceId("scout").tokenStore(tokenStore());
}

对于其他类(class):
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private DataSource dataSource;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.tokenStore(tokenStore());
    }  
}

在 Applications.properties 中,它应该被配置:
spring.datasource.url=jdbc:mysql://localhost:3306/MyDatabase
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

最后,您应该在数据库中添加这两个表:
create table oauth_access_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  authentication BLOB,
  refresh_token VARCHAR(256)
);

create table oauth_refresh_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication BLOB
);

关于spring - 如何在 Spring Security JDBC 中保留 oauth 访问 token ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36904178/

相关文章:

java - Spring Security x509 身份验证成功

java - 可以使用 Spring 安全性根据访问级别隐藏/显示下拉值

java - 如何在 Spring Boot OIDC 应用程序的 Controller 中获取用户详细信息?

oauth - 无法从 Thinktecture 授权服务器获取 token

java - Spring-data-mongodb 不会在列表中保留多个对象

java - 如何获取倒数第二个输入的数据 - 使用 hibernate 保存在 mysql 数据库中

java - 带有 spring 的拦截器 - 上下文初始化失败

asp.net-mvc - 用于 OpenID Connect 的 OWIN 中间件 - 代码流(流类型 - AuthorizationCode)文档?

java - 如何使用 Spring Security 5 在 Spring Boot 应用程序(不是 Web 应用程序)中获取 oauth2 访问 token

java - 无法在 IntelliJ 上使用 2.2.1.BUILD-SNAPSHOT 运行 Spring Initializr