Spring 安全 OAuth2 授权服务器
Spring Security OAuth2 AuthorizationServer
我正在玩 spring-security-oauth2。我尝试构建一些带有身份验证后端的微服务。
我设置了一个简单的 spring 引导项目,其中包含以下依赖项
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
和一种配置Class
@Configuration
public class SecurityConfiguration {
@Autowired
@Qualifier("clientDetailsServiceBean")
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("userDetailsServiceBean")
private UserDetailsService userDetailsService;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true, securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
@Bean(name = "authenticationManagerBean")
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll().and().userDetailsService(userDetailsService).formLogin().and().httpBasic();
}
}
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore());
}
@Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore());
return store;
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("permitAll()");
security.allowFormAuthenticationForClients();
}
}
我对 Client- 和 UserDetailsService 的实现非常简单,而且总是returns一个对象
@Service("clientDetailsServiceBean")
public class ClientDetailsServiceBean implements ClientDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(ClientDetailsServiceBean.class);
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
LOGGER.info("Load client {}", clientId);
BaseClientDetails details = new BaseClientDetails();
details.setClientId(clientId);
details.setAuthorizedGrantTypes(Arrays.asList("password", "refresh_token", "client_credentials"));
details.setScope(Arrays.asList("trust"));
details.setAutoApproveScopes(Arrays.asList("trust"));
details.setAuthorities(Arrays.asList(new SimpleGrantedAuthority("client_role2")));
details.setResourceIds(Arrays.asList("clients"));
details.setClientSecret("secret");
return details;
}
}
@Service("userDetailsServiceBean")
public class UserDetailsServiceBean implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(UserDetailsServiceBean.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("Load user {}", username);
return new User(username, "password", Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")) );
}
}
但是,当我尝试通过
接收 accessToken 时
curl http://localhost:8081/oauth/token -d grant_type=client_credentials -d client_id=web_client -d client_secret=secret
我收到一个错误 "Full authentication is required to access this resource" 并且当我尝试
curl http://localhost:8081/oauth/token -d grant_type=client_credentials -d client_id=web_client -d client_secret=secret --user web_client:secret
我收到一个错误 "Bad credentials"。从我的角度来看,两者都应该有效,但似乎缺少我的配置。
OAuth 还有一些我不清楚的地方:
我尝试使用 spring-security 和自定义登录表单构建一个 spring-mvc 应用程序。是否可以通过 spring 安全性处理令牌请求和刷新周期而无需重定向到身份验证应用程序?
如果是事件驱动的应用程序,是否可以确保令牌有效?如果失败,用户单击按钮并写入一个事件,但处理将在数小时后进行。我如何使用用户凭据处理事件?
你的内心 @Configuration
类 需要是静态的。令我惊讶的是,该应用程序竟然启动了,可能您的整个 SecurityConfiguration
实际上都没有被使用。
It's possible to handle token request and refresh cycles by spring security without redirect to the authentication app?
当然。您是否阅读过规范中的密码和 refresh_token 授权?但是在网络中 UI 强烈建议您使用授权码授权(通过重定向),以便用户只在受信任的地方输入他的凭据。
the user clicks on button and an event is written but the processing of this will be hours later. How can i process the event with the user credentials?
刷新令牌可能是最好的方法。该事件显然需要安全,因为它必须包含刷新令牌。
我正在玩 spring-security-oauth2。我尝试构建一些带有身份验证后端的微服务。
我设置了一个简单的 spring 引导项目,其中包含以下依赖项
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
和一种配置Class
@Configuration
public class SecurityConfiguration {
@Autowired
@Qualifier("clientDetailsServiceBean")
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("userDetailsServiceBean")
private UserDetailsService userDetailsService;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true, securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
@Bean(name = "authenticationManagerBean")
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll().and().userDetailsService(userDetailsService).formLogin().and().httpBasic();
}
}
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore());
}
@Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore());
return store;
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("permitAll()");
security.allowFormAuthenticationForClients();
}
}
我对 Client- 和 UserDetailsService 的实现非常简单,而且总是returns一个对象
@Service("clientDetailsServiceBean")
public class ClientDetailsServiceBean implements ClientDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(ClientDetailsServiceBean.class);
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
LOGGER.info("Load client {}", clientId);
BaseClientDetails details = new BaseClientDetails();
details.setClientId(clientId);
details.setAuthorizedGrantTypes(Arrays.asList("password", "refresh_token", "client_credentials"));
details.setScope(Arrays.asList("trust"));
details.setAutoApproveScopes(Arrays.asList("trust"));
details.setAuthorities(Arrays.asList(new SimpleGrantedAuthority("client_role2")));
details.setResourceIds(Arrays.asList("clients"));
details.setClientSecret("secret");
return details;
}
}
@Service("userDetailsServiceBean")
public class UserDetailsServiceBean implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(UserDetailsServiceBean.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("Load user {}", username);
return new User(username, "password", Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")) );
}
}
但是,当我尝试通过
接收 accessToken 时curl http://localhost:8081/oauth/token -d grant_type=client_credentials -d client_id=web_client -d client_secret=secret
我收到一个错误 "Full authentication is required to access this resource" 并且当我尝试
curl http://localhost:8081/oauth/token -d grant_type=client_credentials -d client_id=web_client -d client_secret=secret --user web_client:secret
我收到一个错误 "Bad credentials"。从我的角度来看,两者都应该有效,但似乎缺少我的配置。
OAuth 还有一些我不清楚的地方: 我尝试使用 spring-security 和自定义登录表单构建一个 spring-mvc 应用程序。是否可以通过 spring 安全性处理令牌请求和刷新周期而无需重定向到身份验证应用程序?
如果是事件驱动的应用程序,是否可以确保令牌有效?如果失败,用户单击按钮并写入一个事件,但处理将在数小时后进行。我如何使用用户凭据处理事件?
你的内心 @Configuration
类 需要是静态的。令我惊讶的是,该应用程序竟然启动了,可能您的整个 SecurityConfiguration
实际上都没有被使用。
It's possible to handle token request and refresh cycles by spring security without redirect to the authentication app?
当然。您是否阅读过规范中的密码和 refresh_token 授权?但是在网络中 UI 强烈建议您使用授权码授权(通过重定向),以便用户只在受信任的地方输入他的凭据。
the user clicks on button and an event is written but the processing of this will be hours later. How can i process the event with the user credentials?
刷新令牌可能是最好的方法。该事件显然需要安全,因为它必须包含刷新令牌。