我正试着前面或者#34;包装"在后端HTTP服务之前的RESTful API服务应用程序。后端服务通过专有会话维护身份验证状态。通过验证客户端和服务器之间的复杂对话来实现与后端服务器的身份验证。通常,与此服务器的交互是非标准的,并且不足以作为API向我们的客户公开。但是,遗留下来并重新引导整个HTTP接口的遗留物太多了。
我的目标是通过使用通过密码授权实现OAuth2身份验证的RESTful服务器将此服务器面向此服务器,从而将接口抽象到此后端服务器,以便第三方API可以以标准且易于理解的方式与后端服务器连接。 我已经构建了一个简单的REST SpringBoot应用程序,可以使用后端进行身份验证。我正在努力解决的部分是弄清楚如何最好地将经过身份验证的令牌/请求映射到后端的会话ID。
本质上,我试图在每个经过身份验证的授权上关联一点状态。 作为一种解决方案,我已经考虑过实现我自己的TokenStore,它将维护映射。或者,我考虑过实施一个"自定义令牌Granter"。但是我有一种强烈的直觉,即有一种更好,更简单的方法来实现我的目标。
其他信息:
@EnableAuthorizationServer
和@EnableResourceServer
属于同一个应用程序。
版本信息:
org.springframework.security.oauth:spring-security-oauth2
2.0.13.RELEASE
org.springframework.security:spring-security-config
4.2.2.RELEASE
org.springframework.boot:spring-boot-starter-security
1.5.3.RELEASE
这是我的资源服务器配置:
@Configuration
@Profile(Common.CONST_EXTAPI_PROFILE)
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and()
.headers().frameOptions().disable().and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/", "/home","/register","/login", "/auth").permitAll()
.antMatchers(HttpMethod.OPTIONS,"/oauth/token").permitAll()
.antMatchers("/extapi/agent", "/extapi/agent/**", "/extapi/account/**", "/extapi/sale/**").authenticated();
}
}
这是我的身份验证服务器配置:
@Configuration
@Profile(Common.CONST_EXTAPI_PROFILE)
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Order(-1)
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
}
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "foobar".toCharArray())
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
{
clients.inMemory()
.withClient("acme")
.autoApprove(true)
.secret("acmesecret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token").scopes("openid");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
自定义身份验证提供程序
@Component
@Profile(Common.CONST_EXTAPI_PROFILE)
public class CustomAuthenticationProvider implements AuthenticationProvider
{
@Autowired
private LoginSessionData sessionData;
@Autowired
private GuiAuthenticationService authService;
@Autowired
private ContextService contextService;
@Autowired
private RSAEncryptionService rsaService;
@Autowired
private ObjectMapper mapper;
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
final String username = auth.getName();
final String password = auth.getCredentials().toString();
Authentication result = null;
DataWrapper oauthResponse = new DataWrapper();
try
{
BaseResponse resp = authService.authenticate(contextService.getCompanyID(), false, null);
oauthResponse.setAuth(rsaService.getPublicKey());
oauthResponse.setData(mapper.writeValueAsString(resp));
if(resp.getState().equals("REQUIRE_UTF8_USERNAME")){
BaseRequest request = new BaseRequest();
request.setData(username);
request.setCid(Integer.toString(contextService.getCompanyID()));
sessionData.captureData(request);
resp = authService.process(request);
}
if(resp.getState().equals("REQUIRE_RSA_PASSWORD"))
{
BaseRequest request = new BaseRequest();
request.setData(password);
request.setCid(Integer.toString(contextService.getCompanyID()));
resp = authService.process(request);
}
if(resp.getState().equals("AUTHENTICATED"))
{
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(username, password, Collections.emptyList());
result = token;
}
}
catch (Exception e)
{
sessionData.setCurrentState(AuthenticationState.INVALID);
oauthResponse.setError(e.getLocalizedMessage());
oauthResponse.setData(Common.CONST_FATAL_ERROR);
e.printStackTrace();
}
if(result == null)
throw new BadCredentialsException("External system authentication failed");
return result;
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
}