Причина, по которой вам нужно подключить AuthenticationManager
, заключается в том, что вы используете поток предоставления password
:
.authorizedGrantTypes("password", ...
С потоком предоставления пароля клиент OAuth2 предоставит вам свои учетные данные клиентаа также имя пользователя / пароль пользователя, и этот пользователь должен быть определен где-то в вашей системе.Возможность аутентификации этих пользователей предоставляется через экземпляр AuthenticationManager
.
На сервере авторизации есть два набора пользователей: клиенты API OAuth2 и конечные пользователи приложения (люди, которыехочу войти).
клиенты определены в классе, который расширяет AuthorizationServerConfigurerAdapter
, который у вас есть.Вы определяете их, когда настраиваете ClientDetailsServiceConfigurer
.
пользователи определены в классе, который расширяет WebSecurityConfigurerAdapter
, что у вас есть , а не .Вы можете определить их и представить соответствующий боб AuthenticationManager
следующим образом ( обратите внимание, что это ваша основная проблема, но есть дополнительные проблемы с вашей конфигурацией, поэтому читайте на ):
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder()
.username("us3r")
.password("pwd")
.roles("USER")
.build());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
Этот последний метод предоставляет боб AuthenticationManager
, так что другие бины Spring могут зависеть от него (например, ваш бин AuthorizationServerConfig
).
Давайте также сделаем некоторую очистку ваших других классов, чтобы уменьшить шум, на случай, если вы столкнетесь с дополнительными препятствиями.
Сначала AuthorizationServerConfig
.Излишне использовать @Configuration
и @Component
.Вы можете просто использовать @Configuration
.Кроме того, это может показаться дополнительной работой, но также полезно использовать хорошие пробелы в Spring Security DSL.Благодаря быстрому API, он очень мощный, но его также легко сделать нечитаемым.
Кроме того, когда вы идете в производство, это будет казаться немного более естественным, но вам нужно указать механизм хеширования, который вы используете для пароля клиента.Поскольку вы сейчас не выполняете хеширование, это может показаться немного странным, но вам нужно добавить его к «{noop}» , чтобы этот пример работал.
И, наконец, 20 секунд достаточно для токена доступа.Я бы порекомендовал хотя бы пару минут, хотя многие токены доступа живут в течение нескольких часов .И если вы хотите, чтобы ваш пользователь должен был повторно входить в систему каждый день, то для обновления токена достаточно 24 часов.По истечении срока действия маркера обновления пользователю необходимо будет снова войти в систему со своими учетными данными.
В зависимости от существующей конфигурации я бы порекомендовал (хотя и следите за обновлениями для некоторых других проблем с этой настройкой):
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig
extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.inMemory()
.withClient("mobile")
.secret("{noop}p@sswd")
.scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(180)
.refreshTokenValiditySeconds(3600 * 24);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
.reuseRefreshTokens(false)
.authenticationManager(authenticationManager);
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter =
new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("algaworks");
return accessTokenConverter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
Теперь я заметил, что имя вашего клиента mobile
. Современная рекомендация для мобильных клиентов - использовать PKCE , который Spring Security пока не поддерживает.Не зная всего о вашем сценарии использования (кажется, что вы просто пытаетесь заставить вещи работать прямо сейчас), тем не менее, я только упомяну, что мобильные приложения не умеют хранить секреты, поэтому вам нужно будет выбрать типы грантов, которые нетребуется мобильное приложение, хранящее клиентские секреты (а password
наверняка требует требует клиентские секреты).
Хорошо, второе, ResourceServerConfig
.Мы можем удалить @EnableWebSecurity
, потому что у нас это есть в нашем новом SecurityConfig
классе.Кроме того, сервер ресурсов обычно не поддерживает набор пользователей (у них есть сервер авторизации), поэтому мы можем удалить первый метод configure
.
Исходя из вашей существующей конфигурации, я бы порекомендовал:
@Configuration
@EnableResourceServer
public class ResourceServerConfig
extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/categorias").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.stateless(true);
}
}
Просто чтобы быть уверенным, я вставил все это в локальный проект в моей IDE, запустил его и смогвыполните следующее:
curl --user "mobile:p@sswd" localhost:8080/oauth/token -dgrant_type=password -dusername=us3r -dpassword=pwd
Который вернулся с токеном:
{ "access_token":"eyJh...",
"token_type":"bearer",
"refresh_token":"eyJh...",
"expires_in":199,
"scope":"read write",
"jti":"09855c19-7a71-4314-bf8f-eb74689d158c" }
Тогда я могу сделать:
export set TOKEN="eyJh..."
Если я тогда сделаю:
curl localhost:8080/yo
Я получаю 401, но если я добавлю токен:
curl -H "Authorization: Bearer $TOKEN" localhost:8080/yo
Я получу 404!
Что, как я понимаю, немного анти-климатическое,но эй, это показывает, что я прошел проверку подлинности.:)
Теперь, когда я сказал все это, если вы все еще читаете, то я также хотел бы отметить, что в зависимости от ваших потребностей Spring Security 5.1 предлагает упрощенный OAuth 2.0 API,У него еще нет сервера авторизации, но у него есть JWT-ресурсный сервер и клиент.Я бы посоветовал вам взглянуть на матрицу функций , чтобы увидеть, есть ли у более новых компонентов функции, которые вам нужны.