默认情况下,在Spring框架中启用OAuth2授权(请参阅下面的配置)并调用/oauth/token
来发出访问令牌时,会发送以下请求:
POST /oauth/token
Authorization: Basic Y34tcF9ib3VpOg==
POST data:
grant_type=password&username=myuser&password=mypass
上面的基本授权是客户ID和客户的秘密,格式如下:
myclient:secret123
然后我可以将此请求发送到Spring的/oauth/check_token
:
POST /oauth/check_token
Authorization: Basic Y34tcF9ib3VpOg==
POST data:
token=the_token_retrieved_from_last_request
这样可以正常工作,并且在提出请求之前会进行基本授权。
请注意,这里的基本授权是Spring JdbcClientDetailsService
,在其中查找名为oauth_client_details
的表,这也很好。
现在由于某种原因,我需要一个自定义的端点,而不是Spring的/ token / check_access。所以我创建了一个类似于Spring CheckTokenEndpoint.java
的控制器,并命名为TokenIntrospectionEndpoint
。我的端点的网址格式设置为/oauth/introspect
:
@Controller
@RequestMapping("/oauth")
public class TokenIntrospectionEndpointImpl {
private RestTemplate restTemplate;
@RequestMapping(value = "/introspect")
@ResponseBody
@Override
public Map<String, ?> introspect(@RequestParam("token") String token) {
// return data
}
}
现在的问题是,在不考虑基本授权的情况下,正在提供对此端点的请求。所以我在配置中添加了这一行:
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/introspect").access("isAuthenticated()");
}
现在Spring的安全性开始了,但是它并没有像对/oauth/check_token
一样处理这个请求,而且我的意思是它不会自动查找表oauth_client_details,就像它对其他的一样与oauth相关的请求。因此,我得到401 http错误代码。
我想我在这里错过了一些东西告诉Spring这是oauth2请求,以便它考虑客户端ID /秘密并自动验证它。任何提示都将不胜感激。
我的配置:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorisationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private MySecuritySettings securitySetting;
@Autowired
private DataSource dataSource;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
//TODO I'd rather not to override Spring's endpoint URL but had issues with authentication.
.pathMapping("/oauth/check_token", "/oauth/introspect").tokenStore(this.tokenStore())
.authenticationManager(authenticationManager)
.tokenServices(tokenServices())
.accessTokenConverter(tokenConverter())
.requestValidator(createOAuth2RequestValidator());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(myClientDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.checkTokenAccess("isAuthenticated()")
.tokenKeyAccess("permitAll()")
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public MyClientDetailsService myClientDetailsService(){
MyClientDetailsService myClientDetailsService = new MyClientDetailsService(dataSource);
myClientDetailsService.setPasswordEncoder(passwordEncoder());
return myClientDetailsService;
}
@Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(tokenConverter());
}
@Bean
public JwtAccessTokenConverter tokenConverter() {
final JwtAccessTokenConverter jwtAccessTokenConverter = new CompJwtAccessTokenConverter();
DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();
defaultAccessTokenConverter.setUserTokenConverter(new CompPrincipalExtractor());
jwtAccessTokenConverter.setAccessTokenConverter(defaultAccessTokenConverter);
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource(securitySetting.getKeystoreFileName()),
securitySetting.getStorepass().toCharArray())
.getKeyPair(securitySetting.getKeyAlias(),
securitySetting.getKeypass().toCharArray());
jwtAccessTokenConverter.setKeyPair(keyPair);
return jwtAccessTokenConverter;
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(securitySetting.isRefreshAccessToken());
tokenServices.setReuseRefreshToken(securitySetting.isReuseRefreshToken());
tokenServices.setTokenEnhancer(tokenConverter());
tokenServices.setAccessTokenValiditySeconds(securitySetting.getAccessTokenValiditySeconds());
return tokenServices;
}
@Bean
@Primary
public OAuth2RequestValidator createOAuth2RequestValidator() {
return new ExpressionBasedOAuth2RequestValidator();
}
}
和此:
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "auth_serv";
@Autowired
TokenStore tokenStore;
@Autowired
MySecuritySettings mySecuritySettings;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/introspect").access("isAuthenticated()")
.and()
.authorizeRequests()
.antMatchers("/api/**/*").access("#oauth2.hasScope('" + mySecuritySettings.getAuthserverScopenameAllAccess() + "')");
}
}