Закодированный пароль не похож на BCrypt

Я использую Spring Boot, Spring Security, OAuth2 и JWT для аутентификации моего приложения, но продолжаю получать эту неприятную ошибку и понятия не имею, что не так. Мой класс CustomDetailsService:

@Service
public class CustomDetailsService implements UserDetailsService {

    private static final Logger logger = LoggerFactory.getLogger(CustomDetailsService.class);

    @Autowired
    private UserBO userBo;

    @Autowired
    private RoleBO roleBo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        AppUsers appUsers = null;
        try {
            appUsers = this.userBo.loadUserByUsername(username);
            System.out.println("========|||=========== "+appUsers.getUsername());
        }catch(IndexOutOfBoundsException e){
            throw new UsernameNotFoundException("Wrong username");
        }catch(DataAccessException e){
            e.printStackTrace();
            throw new UsernameNotFoundException("Database Error");
        }catch(Exception e){
            e.printStackTrace();
            throw new UsernameNotFoundException("Unknown Error");
        }

        if (appUsers == null){
            throw new UsernameNotFoundException("Bad credentials");
        }
        logger.info("Username: "+appUsers.getUsername());
        return buildUserFromUserEntity(appUsers);
    }

    private User buildUserFromUserEntity(AppUsers authUsers) {
        Set<UserRole> userRoles = authUsers.getUserRoles();

        boolean enabled = true;
        boolean accountNotExpired = true;
        boolean credentialsNotExpired = true;
        boolean accountNotLocked = true;

        if (authUsers.getAccountIsActive()) {
            try {
                if (authUsers.getAccountExpired()){
                    accountNotExpired = true;
                } else if (authUsers.getAccountIsLocked()) {
                    accountNotLocked = true;
                } else {
                    if (containsRole((userRoles), roleBo.findRoleByName("FLEX_ADMIN"))){
                        accountNotLocked = false;
                    }
                }
            }catch(Exception e){
                enabled = false;
                e.printStackTrace();
            }
        }else {
            accountNotExpired = false;
        }
        // convert model user to spring security user
        String username = authUsers.getUsername();
        String password = authUsers.getPassword();

        List<GrantedAuthority> authorities = buildUserAuthority(userRoles);

        User springUser = new User(username, password,enabled, accountNotExpired, credentialsNotExpired, accountNotLocked, authorities);
        return springUser;
    }
}

OAuth2Config:

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Bean
    public JwtAccessTokenConverter tokenConverter() {
        JwtAccessTokenConverter tokenConverter = new JwtAccessTokenConverter();
        tokenConverter.setSigningKey(PRIVATE_KEY);
        tokenConverter.setVerifierKey(PUBLIC_KEY);
        return tokenConverter;
    }

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(tokenConverter());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpointsConfigurer) throws Exception {
        endpointsConfigurer.authenticationManager(authenticationManager)
                .tokenStore(tokenStore())
                .accessTokenConverter(tokenConverter());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer securityConfigurer) throws Exception {
        securityConfigurer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient(CLIENT_ID)
                .secret(CLIENT_SECRET)
                .scopes("read","write")
                .authorizedGrantTypes("password","refresh_token")
                .accessTokenValiditySeconds(20000)
                .refreshTokenValiditySeconds(20000);
    }
}

SecurityConfig:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomDetailsService customDetailsService;

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Autowired
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(customDetailsService).passwordEncoder(encoder());
        System.out.println("Done...finito");
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.NEVER);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManagerBean();
    }
}

Нет сообщения об ошибке, кроме:

Hibernate: select appusers0_.id as id1_2_, appusers0_.account_expired as account_2_2_, appusers0_.account_is_active as account_3_2_, appusers0_.account_is_locked as account_4_2_, appusers0_.bank_acct as bank_acc5_2_, appusers0_.branch_id as branch_i6_2_, appusers0_.bvn as bvn7_2_, appusers0_.create_date as create_d8_2_, appusers0_.created_by as created_9_2_, appusers0_.email as email10_2_, appusers0_.email_verified_code as email_v11_2_, appusers0_.gender as gender12_2_, appusers0_.gravatar_url as gravata13_2_, appusers0_.is_deleted as is_dele14_2_, appusers0_.lastname as lastnam15_2_, appusers0_.middlename as middlen16_2_, appusers0_.modified_by as modifie17_2_, appusers0_.modified_date as modifie18_2_, appusers0_.orgnization_id as orgniza19_2_, appusers0_.password as passwor20_2_, appusers0_.phone_no as phone_n21_2_, appusers0_.surname as surname22_2_, appusers0_.token_expired as token_e23_2_, appusers0_.username as usernam24_2_ from users appusers0_ where appusers0_.username=?
Tinubu
2018-03-31 01:42:03.255  INFO 4088 --- [nio-8072-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-03-31 01:42:03.255  INFO 4088 --- [nio-8072-exec-2] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2018-03-31 01:42:03.281  INFO 4088 --- [nio-8072-exec-2] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 26 ms
2018-03-31 01:42:03.489  WARN 4088 --- [nio-8072-exec-2] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt

Мои классы модели сущностей:

@Entity
@Table(name = "USERS")
@DynamicUpdate
public class AppUsers {

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @ApiModelProperty(notes = "The user auto generated identity", required = true)
    private Long id;

    @Column(name = "username")
    @ApiModelProperty(notes = "The username parameter", required = true)
    private String username;

    @Column(name = "password")
    @ApiModelProperty(notes = "The password parameter", required = true)
    private String password;

    @JsonManagedReference
    @OneToMany(mappedBy = "appUsers")
    private Set<UserRole> userRoles;

'''''' setters and getters
}

Сущность Role:

@Entity
@Table(name = "ROLE")
public class Role {

    @javax.persistence.Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id", unique = true, nullable = false)
    private Long Id;

    @Column(name = "name")
    private String roleName;

   @JsonManagedReference
    @OneToMany(mappedBy = "role")
    private Set<UserRole> userRoles;

   //getters and setters

}

Сущность UserRole:

@Entity
@Table(name = "USER_ROLE")
@DynamicUpdate
public class UserRole   implements Serializable {

    private static final long serialVersionUID = 6128016096756071383L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @ApiModelProperty(notes = "The userrole auto generated identity", required = true)
    private long id;

    @JsonBackReference
    @ManyToOne//(fetch=FetchType.LAZY)
    private AppUsers appUsers;

    @JsonBackReference
    @ManyToOne//(fetch=FetchType.LAZY)
    private Role role;

   // getters and setters
}

Мой пароль в базе данных правильно зашифрован Spring security BCrypt, а его тип данных - varchar (255), который больше 60.

@Min Hyoung Hong .. Код работал нормально, пока мне не понадобились учетные данные для аутентификации. единственная ошибка, которую он выдает: (Закодированный пароль не похож на BCrypt)

Kunle Ajiboye 31.03.2018 03:18
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
37
1
58 608
19
Перейти к ответу Данный вопрос помечен как решенный

Ответы 19

Вероятно, вам не хватает этого bean-компонента в вашей конфигурации безопасности SecurityConfig.

@Bean
public DaoAuthenticationProvider getAuthenticationProvider() {
    DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
    authenticationProvider.setUserDetailsService(customDetailsService);
    authenticationProvider.setPasswordEncoder(encoder());
    return authenticationProvider;
}

UserDetaulsService и PasswordEncoder уже определены в protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder). Разве этого не достаточно?

misabelcarde 01.04.2018 20:12

Можете ли вы дважды проверить, закодирован ли секрет вашего клиента?

@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
    configurer
            .inMemory()
            .withClient(clientId)
            .secret(passwordEncoder.encode(clientSecret))
            .authorizedGrantTypes(grantType)
            .scopes(scopeRead, scopeWrite)
            .resourceIds(resourceIds);
}

Черт, это сработало для меня! Не могли бы вы объяснить, почему нам также нужно кодировать пароль клиента?

Ayush28 02.10.2020 16:20

PasswordEncoder должен быть установлен следующим образом:

@Bean
public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

Вы правы .. но это приводит к другой проблеме java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

Pra_A 01.01.2019 16:28

Вы можете зашифровать секрет клиента, например {bcrypt} $ 2a ...... Надеюсь, это сработает!

amran_bd 31.01.2019 10:52

У меня была такая же ошибка, и это было из-за типа данных столбца пароля, длина этого столбца была фиксированной (CHARACTER), поэтому убедитесь, что вы используете тип данных VARCHAR, или измените длину на 60 для столбца пароля.

Когда зависимости oauth2 переместились в облако, я столкнулся с этой проблемой. Раньше это было частью системы безопасности:

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
</dependency>

Теперь это часть облачного фреймворка:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

Поэтому, если вы используете облачную зависимость (Finchley.RELEASE), вам может потребоваться кодировать секрет, как показано ниже:

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients
            .inMemory()
            .withClient("clientapp")
            .authorizedGrantTypes("password","refresh_token")
            .authorities("USER")
            .scopes("read", "write")
            .resourceIds(RESOURCE_ID)
            .secret(passwordEncoder.encode("SECRET"));
}
Ответ принят как подходящий

BCryptPasswordEncoder показывает это предупреждение, когда не удается сопоставить необработанный пароль с закодированным паролем.

Теперь хешированный пароль может быть «2 миллиарда долларов» или «2 года».

И в Spring Security есть ошибка, из-за которой регулярное выражение всегда ищет «$ 2a». Поместите точку отладки в функцию matches() в BCryptPasswordEncoder.class.

Я столкнулся с этой проблемой прямо сейчас. Я хешировал пароли с помощью онлайн-инструментов, и если хешированный пароль начинается с 2 или 2 млрд долларов, я получаю «Закодированный пароль не похож на BCrypt». Единственный способ избежать этой ошибки - использовать хешированные пароли, начинающиеся с $ 2a.

Lucas. D 07.10.2018 19:49

К вашему сведению, ошибка была обнаружена на GitHub: github.com/spring-projects/spring-security/issues/3320. Похоже, PR был объединен в октябре 2018 года (через 3 года после отчета об ошибке и через 4 года после обновления BCrypt). Вероятно, он будет выпущен с новой версией безопасности Spring (5.2.0)

rwenz3l 11.12.2018 09:48

Spring-core-security версии 5.0.11, класс BCryptPasswordEncoder, метод "соответствует" с использованием "частного шаблона BCRYPT_PATTERN = Pattern .compile (" \\ A \\ $ 2a? \\ $ \\ d \\ d \\ $ [. / 0-9A-Za-z] {53} ");" попадет в блок: if (! BCRYPT_PATTERN.matcher (encodedPassword) .matches ()) {logger.warn («Закодированный пароль не похож на BCrypt»); вернуть ложь; }

Do Tat Hoan 04.07.2019 10:55

Пожалуйста, проверьте, возвращает ли ваш метод UserDetails loadUserByUsername(String username) действительный объект UserDetail. Если возвращенный объект является нулевым / объектом с недопустимыми значениями, вы также увидите эту ошибку.

BCryptPasswordEncoder не удаляет идентификатор {bcrypt}, но DelegatingPasswordEncoder это делает. Когда я явно определяю BCryptPasswordEncoder в качестве кодировщика для DaoAuthenticationProvider, он вызывает метод совпадений на BCryptPasswordEncoder (без полосы идентификатора), но не на DelegatingPasswordEncoder (с полосой идентификатора).

Лучший способ идентифицировать эту проблему «Закодированный пароль не похож на BCrypt» - это установить перерыв в классе org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder. Затем проверьте первопричину предупреждения.

if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
    logger.warn("Encoded password does not look like BCrypt");
    return false;
}

Для моего сообщения об ошибке «Закодированный пароль не похож на BCrypt». Длина кодируемого пароля составляет 60 байт. Но пароль столбца в базе данных - 100. Поэтому я изменил пароль столбца с char на varchar, чтобы исправить эту проблему.

Lin Chen 23.03.2019 04:00

моя база данных - db2 на iseries.

Lin Chen 23.03.2019 04:05

используйте noop в секрете для тестов.

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
            .withClient("angular")
            .secret("{noop}@ngular0")
            .scopes("read", "write")
            .authorizedGrantTypes("password")
            .accessTokenValiditySeconds(1800);
}

На сегодняшний день с Spring Boot 2.1.7.RELEASE я все еще испытываю эту проблему. Я использовал некоторые онлайн-инструменты, которые давали мне хеши от 2 до 2 лет, что Spring BCryptPasswordEncoder не позволяет:

public class BCryptPasswordEncoder implements PasswordEncoder {
    private Pattern BCRYPT_PATTERN = Pattern
            .compile("\\A\\$2a?\\$\\d\\d\\$[./0-9A-Za-z]{53}");
...

Решение: используйте класс BCryptPasswordEncoder для кодирования пароля:

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
System.out.println(encoder.encode("admin"));

А потом:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
        throws Exception {
    auth.inMemoryAuthentication()
            .withUser("admin")
            .password("{bcrypt}$2a$10$6CW1agMzVzBhxDzK0PcxrO/cQcmN9h8ZriVEPy.6DJbVeyATG5mWe")
            .roles("ADMIN");
}

В Spring Security 5 кодировщиком по умолчанию является DelegatingPasswordEncoder, который требует формата хранения паролей.

Прочитать это

    private PasswordEncoder delegateEncoder =
            PasswordEncoderFactories.createDelegatingPasswordEncoder();

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception{
            clients
                    .jdbc(dataSource)
                    .passwordEncoder(delegateEncoder);
    }

Сгенерируйте код password или secret, используя кодировщик по умолчанию, которым является DelegatingPasswordEncoder.

System.out.println(delegateEncoder.encode("123123"));
// it generates the encoded code something like this: 
// {bcrypt}$2a$10$0aISzamI0jBCVTxONzJlHOk7O7QS.XPFIheLVhXultVa9Ju7SarZ6

Я избавился от этого сообщения об ошибке, используя длинный пароль из 60 символов, например CXPW3XT2vXwBZk9mYZ5eCrKPM8kXJC6bbwJQjtGq2NQRYQPzsvqTwYz8JvWhWD5KLrrUHHammBNV3tkkyA4U

Обновите поле client_secret в таблице oauth_client_details на BCryptPasswordEncoder, если вы переносите весеннюю загрузку с 1x на 2x. Чтобы закодировать секретное использование:

    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    String password = "12345678";
    String encodedPassword = passwordEncoder.encode(password);

    System.out.println();
    System.out.println("Password is         : " + password);
    System.out.println("Encoded Password is : " + encodedPassword);
    System.out.println();

    boolean isPasswordMatch = passwordEncoder.matches(password, encodedPassword);
    System.out.println("Password : " + password + "   isPasswordMatch    : " + isPasswordMatch);
  1. Если вы добавили "{bcrypt}" прямо перед паролем и не настроили приложение соответствующим образом, вы получите эту ошибку. Подумайте об удалении этого.
  2. Если все еще не решено, просто установите длину столбца пароля пользователя на 60 (68, если вы добавили {bcryt} в начале). Сработало для меня!

Для моего аналогичного сценария я просто закодировал пароль, подобный этому passwordEncoder().encode("password"), вместо необработанной строки "password":

authenticationManagerBuilder
  .inMemoryAuthentication()
  .withUser("user")
  // Just changed here
  .password(passwordEncoder().encode("password"))
  .roles("USER");


@Bean
public PasswordEncoder passwordEncoder() {
  return new BCryptPasswordEncoder();
}

Я боролся с этой ошибкой во время прохождения курса Spring Security.

Моя проблема заключалась в том, что, хотя в AuthenticationManager я использовал кодировку, например:

    @Autowired
    public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

Проблема заключалась в том, что я не кодировал пароль, когда сохранял пользователей !! Пример:

final Principal entity = new Principal(loginName, passwordEncoder.encode(pass), roles);

Сущность UserDetails должна возвращать закодированный пароль. Это зависит от реализации.

class MyUserDetails: UserDetails {

    //...

    override fun getPassword(): String {
        return passwordEncoder().encode("aPassword")
    }

    private fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

}

GL

У меня была такая же проблема, и проблема в том, что вы должны закодировать свой пароль inMemory, потому что, когда вы нажимаете форму входа, Spring Security автоматически берет извлеченный пароль из заголовка HTTP Basic Auth, хэш и сравнивает его с хешированным паролем из вашего объекта UserDetails. Если оба совпадают, пользователь успешно аутентифицирован, иначе вы получите эту ошибку.

Например ,

InMemory Password = "123"
passwordEncoder.encode ("123")

Ссылка: ссылка на сайт

Другие вопросы по теме