ПРИМЕР КОДА, ПОМОГАЮЩИЙ РЕШИТЬ ПРОБЛЕМУ: https://github.com/Suwappertjes/SpringSample
Проблема
При попытке реализовать jwt-security в приложении Spring Boot я столкнулся со следующей проблемой:
Когда я пытаюсь войти в систему с x-www-форма-urlencoded через Postman, я получаю сообщение об ошибке "Неправильные учетные данные клиента", хотя я знаю, что учетные данные верны.
Когда я смотрю в свой журнал, я вижу, что BCrypt дал Предупреждение «Пустой закодированный пароль». Это странно, учитывая, что я вижу правильно зашифрованные пароли в базе данных, когда смотрю на нее через интерпретатор MySQL.
Информация
Я использую Hibernate для создания базы данных MySQL.
скомпилировать «org.springframework.security.oauth: spring-security-oauth2: 2.3.6.RELEASE»
скомпилировать «org.springframework.security: spring-security-jwt: 1.0.10.RELEASE»
скомпилировать 'org.springframework.boot: spring-boot-starter-data-jpa'
Ява 1.8.0_212
Что я пробовал
Прежде чем приступить к реализации безопасности, контроллеры, репозитории и база данных MySQL работали правильно.
Когда я ищу эту проблему в Интернете, некоторые люди предполагают, что это связано с функцией «loadUserByUsername». Но когда я отлаживаю эту функцию, я замечаю, что это вообще не звонят.
Я также пробовал разрешение каждого пути в моей программе И отключение crsf
на случай, если это как-то связано с правами доступа, но оба ничего не меняли. (http.requestMatchers.andMatcher("/**").permitAll().and().csrf().disable();)
Обновление: при помещении НЕТ пользователей в базу данных я все еще получаю ту же ошибку.
Некоторый код:
Метод loadUserByUsername:
@Override
public UserDetails loadUserByUsername(String userName) {
return userRepository.findByUsername(userName)
.map(user -> new User(
user.getUsername(),
user.getPassword(),
UserRoleAuthority.getAuthorities(user.getRoles())
))
.orElseThrow(() -> new UsernameNotFoundException("Unknown user: " + userName));
}
Провайдер аутентификации и кодировщик паролей:
@Bean
public DaoAuthenticationProvider getAuthenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Ключ подписи:
@Bean
public JwtAccessTokenConverter jwtTokenEnhancer() {
JwtAccessTokenConverter result = new JwtAccessTokenConverter();
result.setSigningKey(signingKey);
return result;
}
Добавление нового пользователя:
userRepository.save(new User()
.withUsername("test")
.withPassword(passwordEncoder.encode("password"))
.withFirst("Admin")
.withLast("Nator")
.withEmail("[email protected]")
.withRole(new HashSet<>(Arrays.asList(Role.Admin, Role.NotAdmin)))
);
И конфигурация http:
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/iungo/*/**")
.and()
.authorizeRequests()
.antMatchers("/iungo/system/**")
.permitAll()
.antMatchers("/iungo/**");
}
@Override
public void configure(HttpSecurity http) throws Exception {
// We don't use this endpoint but we have to define it anyway in order to not enable web security on the whole application.
http
.userDetailsService(userDetailsService)
.requestMatchers()
.antMatchers("/oauth/authorize");
}
И, наконец, мой приставка:
2019-06-12 10:29:58.460 INFO 25207 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.9.Final}
2019-06-12 10:29:58.461 INFO 25207 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2019-06-12 10:29:58.532 INFO 25207 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-06-12 10:29:58.599 INFO 25207 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2019-06-12 10:29:59.092 INFO 25207 --- [ main] o.h.t.schema.internal.SchemaCreatorImpl : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@c30f26d'
2019-06-12 10:29:59.098 INFO 25207 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-06-12 10:29:59.382 WARN 25207 --- [ main] o.s.s.o.p.t.s.JwtAccessTokenConverter : Unable to create an RSA verifier from verifierKey (ignoreable if using MAC)
2019-06-12 10:29:59.595 INFO 25207 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@56a72887, org.springframework.security.web.context.SecurityContextPersistenceFilter@1ddba7a0, org.springframework.security.web.header.HeaderWriterFilter@7adbec34, org.springframework.security.web.authentication.logout.LogoutFilter@296bfddb, org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter@22ab1b8a, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@54033a65, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7dfec0bc, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@42734b71, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3c8dea0b, org.springframework.security.web.session.SessionManagementFilter@6fe9c048, org.springframework.security.web.access.ExceptionTranslationFilter@526fc044, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@690e4b00]
2019-06-12 10:29:59.600 INFO 25207 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/iungo/*/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1978b0d5, org.springframework.security.web.context.SecurityContextPersistenceFilter@69a3bf40, org.springframework.security.web.header.HeaderWriterFilter@3186f8f5, org.springframework.security.web.authentication.logout.LogoutFilter@a4dcede, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@760c777d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2c731a16, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@2a341e3d, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6556471b, org.springframework.security.web.session.SessionManagementFilter@467cd4b9, org.springframework.security.web.access.ExceptionTranslationFilter@3f3f554f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@d0e4972]
2019-06-12 10:29:59.603 INFO 25207 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/authorize']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@6cf3b3d7, org.springframework.security.web.context.SecurityContextPersistenceFilter@462f8fe9, org.springframework.security.web.header.HeaderWriterFilter@24f2608b, org.springframework.security.web.csrf.CsrfFilter@713497cd, org.springframework.security.web.authentication.logout.LogoutFilter@56193e3a, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3c6fc4cd, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@b2e1df3, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2e785b28, org.springframework.security.web.session.SessionManagementFilter@12a9e864, org.springframework.security.web.access.ExceptionTranslationFilter@4b762988]
2019-06-12 10:29:59.731 INFO 25207 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-06-12 10:29:59.902 INFO 25207 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-06-12 10:29:59.903 INFO 25207 --- [ main] nl.highway.iungomain.Application : Started Application in 2.937 seconds (JVM running for 3.345)
2019-06-12 10:29:59.923 INFO 25207 --- [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2019-06-12 10:30:12.550 INFO 25207 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-06-12 10:30:12.550 INFO 25207 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-06-12 10:30:12.554 INFO 25207 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
2019-06-12 10:30:12.632 WARN 25207 --- [nio-8080-exec-1] o.s.s.c.bcrypt.BCryptPasswordEncoder : Empty encoded password
Не могли бы вы уточнить?
У вас есть этот метод: @Override public void configure (конечные точки AuthorizationServerEndpointsConfigurer) в расширении класса: AuthorizationServerConfigurerAdapter
Да, с .tokenStore(tokenStore()).accessTokenConverter(jwtTokenEnhancer()).authenticationManager(authManager);, где authManger просто private final AuthenticationManager authManager;
@Suwappertjes может помочь образец. Не могли бы вы опубликовать образец на GitHub - я был бы рад взглянуть.
@jzheaux Это было бы здорово! Я создаю небольшой образец с той же проблемой. Дополнительную информацию см. в файле Readme: github.com/Suwappertjes/SpringSample.




вам нужно добавить bCryptPasswordEncoder в методе configureGlobal
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
Спасибо за совет! Я добавил этот блок кода, но, к сожалению, ничего не изменилось
Я нашел проблему. Я использовал Spring boot 2.1.4.RELEASE, но эта настройка работает только в 1.5.12.RELEASE. Конечно, переход на более раннюю версию не очень хорошая практика, поэтому я все же попытаюсь заставить ее работать с 2.1.4.
Я думаю, что решение @ghazouanbadr правильное. Хотя в своем практическом проекте я реализовал это иначе:
@EnableWebSecurity
@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserService userService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Override // Authorization
protected void configure(HttpSecurity http) throws Exception {
...
}
@Override // Authentication
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userService(userService).passwordEncoder(bCryptPasswordEncoder);
}
}
Имейте в виду, что я только около месяца изучал Java, когда создал этот класс. Не слишком много помню о безопасности, поэтому не мне говорить вам, что это лучший способ сделать это. Поскольку я помню, как имел дело с той же проблемой, я подумал, что это может направить вас в правильном направлении.
Я столкнулся с точно такой же проблемой. В моем случае причиной был мой конструктор класса CustomUserDetails, который не устанавливал пароль для класса, поэтому он всегда был нулевым.
Кредиты этому ответчику: почему Spring Security дает пустой пароль кодировщику паролей?
Вы пробовали использовать базовую аутентификацию?