Я пытаюсь создать приложение Spring, использующее токены JWT и протокол OAuth2. У меня работает сервер аутентификации благодаря это руководство. Однако мне трудно заставить сервер ресурсов работать должным образом. Из следования за статьей и благодаря ответу на предыдущий вопрос, это моя текущая попытка:
Конфигурация безопасности для сервера ресурсов:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.signing-key}")
private String signingKey;
@Value("${security.encoding-strength}")
private Integer clientID;
@Value("${security.security-realm}")
private String securityRealm;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setVerifierKey(signingKey);
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean ResourceServerTokenServices tokenService() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Override
public AuthenticationManager authenticationManager() throws Exception {
OAuth2AuthenticationManager authManager = new OAuth2AuthenticationManager();
authManager.setTokenServices(tokenService());
return authManager;
}
}
Конфигурация сервера ресурсов:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private ResourceServerTokenServices tokenServices;
@Value("${security.jwt.resource-ids}")
private String resourceIds;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(resourceIds).tokenServices(tokenServices);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().and().authorizeRequests().antMatchers("/actuator/**", "/api-docs/**").permitAll()
.antMatchers("/**").authenticated();
}
}
Конфигурация безопасности для сервера авторизации (из указанного руководства):
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.signing-key}")
private String signingKey;
@Value("${security.encoding-strength}")
private Integer encodingStrength;
@Value("${security.security-realm}")
private String securityRealm;
@Autowired
private UserDetailsService userDetailsService;
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new ShaPasswordEncoder(encodingStrength));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName(securityRealm)
.and()
.csrf()
.disable();
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
@Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}
Теперь, когда я пытаюсь сделать запрос к серверу ресурсов, я получаю следующее сообщение об ошибке:
{"error":"invalid_token","error_description":"Invalid access token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdGp3dHJlc291cmNlaWQiXSwidXNlcl9uYW1lIjoiam9obi5kb2UiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXh
wIjoxNTE1MTE3NTU4LCJhdXRob3JpdGllcyI6WyJTVEFOREFSRF"}
У меня есть пара вопросов:
- Насколько я понимаю, проблема часто связана с хранилищами токенов. Как справиться с разделением серверов при использовании JwtTokenStore?
- Во-вторых, в настоящее время мое приложение Resource полагается на доступ к ключу. Насколько я понимаю спецификации JWT и 0Auth, в этом нет необходимости. Скорее, я должен иметь возможность делегировать проверку самому серверу аутентификации. Из документации Spring я подумал, что следующее свойство может быть применимо
security.oauth2.resource.token-info-uri=http://localhost:8080/oauth/check_token
. Однако, если я попытаюсь не полагаться на ключ с моим сервером ресурсов, я столкнусь с трудностями при установке моего ResourceServerTokenService. Служба ожидает хранилище токенов, JWTTokenStore использует JwtAccessTokenConverter, а конвертер использует ключ (удаление ключа привело к той же ошибкеinvalid token
, которую я испытал ранее).
Я действительно изо всех сил пытаюсь найти статьи, которые показывают, как разделить сервер аутентификации и ресурсов. Любой совет будет принят во внимание.
РЕДАКТИРОВАТЬ: На самом деле код для сервера ресурсов теперь не компилируется со следующим сообщением:
Caused by: java.lang.IllegalStateException: For MAC signing you do not need to specify the verifier key separately, and if you do it must match the signing key
@Configuration
, помеченный@EnableResourceServer
и расширяющийResourceServerConfigurerAdapter
. У другого был класс@Configuration
, помеченный знаком@EnableAuthorizationServer
и расширяющийAuthorizationServerConfigurerAdapter
. Учебное пособие, упомянутое в первом посте, содержит очень полезную информацию для начала работы. Надеюсь это поможет. - person KellyM   schedule 02.04.2019