前言
我正在开发OAuth
两台服务器之间的安全应用程序。我有一个OAuth Server
和一个Resource Server
。有Resource Server
一个.war
部署,其中包含4 APIs
.
单一职责
OAuth server
必须验证由(4 个中的 1 个)从相同的传递access token
的。API
.war
OAuth server
必须hit count
为特定的accessToken
特定保留一个API
。如果hit count
超出配置hits
,OAuth server
将抛出403: Forbidden。- 每个
API
人都.war
必须首先验证accessToken
来自OAuth server
,如果它被验证,然后继续提供响应。
我做了什么:
如果 a.war
有一个,API
那么我可以简单地使两个服务器使用 a 进行通信webHook
,下面是执行此操作的代码。
在资源服务器端:
我的不同 API 的网址是:
localhost:8080/API/API1
localhost:8080/API/API2
下面的代码路由任何请求,如果他们/API/anything
有spring security filters
<http pattern="/API/**" create-session="never" authentication-manager-ref="authenticationManager" entry-point-ref="oauthAuthenticationEntryPoint" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/places/**" method="GET" access="IS_AUTHENTICATED_FULLY" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
我使用了远程令牌服务并定义了webHook
将请求路由到OAuth server
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.RemoteTokenServices">
<property name="checkTokenEndpointUrl" value="http://localhost:8181/OUTPOST/oauth/check_token"/>
<property name="clientId" value="atlas"/>
<property name="clientSecret" value="atlas"/>
</bean>
身份验证服务器的配置
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private static String REALM="OUTPOST_API";
@Autowired
private ClientDetailsService clientService;
@Autowired
public AuthorizationServerConfig(AuthenticationManager authenticationManager,RedisConnectionFactory redisConnectionFactory) {
this.authenticationManager = authenticationManager;
this.redisTokenStore = new RedisTokenStore(redisConnectionFactory);
}
// @Autowired
// @Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
private TokenStore redisTokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("isAuthenticated()").
realm(REALM+"/client");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("cl1")
.secret("pwd")
.authorizedGrantTypes("password", "client_credentials", "refresh_token")
.authorities("ROLE_CLIENT", "ROLE_ADMIN")
.scopes("read", "write", "trust")/*
.resourceIds("sample-oauth")*/
.accessTokenValiditySeconds(1000)
.refreshTokenValiditySeconds(5000)
.and()
.withClient("atlas")
.secret("atlas");
}
@Bean
@Autowired
public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory) {
this.redisTokenStore = new RedisTokenStore(redisConnectionFactory);
return this.redisTokenStore;
}
@Bean
public WebResponseExceptionTranslator loggingExceptionTranslator() {
return new DefaultWebResponseExceptionTranslator() {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
// This is the line that prints the stack trace to the log. You can customise this to format the trace etc if you like
e.printStackTrace();
// Carry on handling the exception
ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
HttpHeaders headers = new HttpHeaders();
headers.setAll(responseEntity.getHeaders().toSingleValueMap());
OAuth2Exception excBody = responseEntity.getBody();
return new ResponseEntity<>(excBody, headers, responseEntity.getStatusCode());
}
};
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(redisTokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager)
.exceptionTranslator(loggingExceptionTranslator());
}
public void setRedisConnectionFactory(RedisConnectionFactory redisConnectionFactory) {
this.redisConnectionFactory = redisConnectionFactory;
}
@Bean
public TokenStoreUserApprovalHandler userApprovalHandler(){
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(redisTokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientService));
handler.setClientDetailsService(clientService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(redisTokenStore);
return store;
}
@Bean
@Primary
@Autowired
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(redisTokenStore);
return tokenServices;
}
}
@Component
class MyOAuth2AuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint{}
我需要帮助:
问题在于对 single.war
和multiple API
. 问题是 spring 配置是在包级别创建的,因为所有的APIs
都.war
具有相同的clientID
和clientSecret
.
我的 OAuth 服务器如何知道,API
正在访问哪些具体内容以及API
需要hitCount
扣除哪些内容。
可能的解决方案?
我正在考虑在服务器上自定义RemoteTokenService
和添加请求参数,webHoot URL
然后在OAuth
服务器上使用过滤器来获取传递tag
(如果我可以这样称呼它)
这甚至可能吗?有没有比这更好的方法,不涉及所有这些工作?