如何在 spring 安全性 JDBC 中保留 oauth 访问令牌?
How to persist oauth access tokens in spring security JDBC?
当用户登录时,我会生成一个令牌,这样当用户想要访问 RESTapi 的信息时,他将不会再次登录,代码可以工作,但我遇到了问题。
spring 生成的令牌有效,但是当我重新编译我编写的代码时,此令牌不再有效,我应该请求一个新令牌来使用 "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();
}
}
}
默认情况下,内存令牌存储已配置。如果你想在重启之间保留令牌,那么你需要配置一个持久令牌存储(例如 JdbcTokenStore)
编辑以添加步骤:
This SQL will create the basic schema that you need.
创建一个连接到包含该模式的数据库的数据源 bean,然后将以下 bean 添加到您的 OAuth 配置中
@Autowired
DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
要解决这个问题,你应该添加一个令牌存储来持久化每次生成的令牌:
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
);
当用户登录时,我会生成一个令牌,这样当用户想要访问 RESTapi 的信息时,他将不会再次登录,代码可以工作,但我遇到了问题。
spring 生成的令牌有效,但是当我重新编译我编写的代码时,此令牌不再有效,我应该请求一个新令牌来使用 "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();
}
}
}
默认情况下,内存令牌存储已配置。如果你想在重启之间保留令牌,那么你需要配置一个持久令牌存储(例如 JdbcTokenStore)
编辑以添加步骤:
This SQL will create the basic schema that you need.
创建一个连接到包含该模式的数据库的数据源 bean,然后将以下 bean 添加到您的 OAuth 配置中
@Autowired
DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
要解决这个问题,你应该添加一个令牌存储来持久化每次生成的令牌:
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
);