Java 编码密码看起来不像 BCrypt

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49582971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 03:04:07  来源:igfitidea点击:

Encoded password does not look like BCrypt

javaspringspring-bootspring-data-jpa

提问by Kunle Ajiboye

I am using Spring Boot, Spring Security, OAuth2 and JWT to authenticate my application, but I keep getting this nasty error and I don't have any idea what is wrong. My CustomDetailsServiceclass:

我正在使用 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:

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:

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();
    }
}

No error message except:

没有错误消息,除了:

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

My entity model classes are:

我的实体模型类是:

@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
}

Roleentity:

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

}

UserRoleentity:

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
}

My password in the database is properly encrypted Spring security BCrypt and it datatype is varchar(255) which is larger than 60.

我在数据库中的密码是正确加密的 Spring security BCrypt,它的数据类型是大于 60 的 varchar(255)。

采纳答案by Nikhil

BCryptPasswordEncoder shows this warning when it fails to match a raw password with an encoded password.

当 BCryptPasswordEncoder 无法将原始密码与编码密码匹配时,它会显示此警告。

The hashed password might be “$2b” or “$2y” now.

散列密码现在可能是“$2b”或“$2y”。

And there is a bug in Spring Security that has a regex always looking for “$2a”. Put a debug point at the matches()function in the BCryptPasswordEncoder.class.

Spring Security 中有一个错误,它的正则表达式总是在寻找“$2a”。将一个调试点处matches()的功能BCryptPasswordEncoder.class

回答by bitscanbyte

You are likely missing this bean in your Security configuration SecurityConfig

您可能在安全配置中缺少此 bean SecurityConfig

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

回答by Selvam Paramasivan

Can you double check your client secret is encoded?

您可以仔细检查您的客户端密码是否已编码?

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

回答by Pascal Joret

The PasswordEncoder should be set like this:

PasswordEncoder 应该像这样设置:

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

回答by Christian Altamirano Ayala

I had the same error and it was because of the datatype of the password column, this column was length blank fixed (CHARACTER), so make sure You're using a VARCHAR datatype or else change the length to 60 for you password column.

我遇到了同样的错误,这是因为密码列的数据类型,该列的长度为空白固定(CHARACTER),因此请确保您使用的是 VARCHAR 数据类型,否则将密码列的长度更改为 60。

回答by PKumar

When oauth2 dependecncies moved to cloud, I started facing this issue. Earlier it was part of security framework :

当 oauth2 依赖项迁移到云时,我开始面临这个问题。早些时候它是安全框架的一部分:

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

Now it is part of cloud framework :

现在它是云框架的一部分:

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

So if you are using cloud dependency (Finchley.RELEASE) then you may need to encode the secret like below :

因此,如果您正在使用云依赖 (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"));
}

回答by sandeep pandey

Please check if your method UserDetails loadUserByUsername(String username)returns valid UserDetailobject. If Returned object is null / object with invalid values then also you will see this error.

请检查您的方法是否UserDetails loadUserByUsername(String username)返回有效的UserDetail对象。如果返回的对象为空/具有无效值的对象,那么您也会看到此错误。

回答by Zagrebin Victor

BCryptPasswordEncoder does not strip the {bcrypt} id, but DelegatingPasswordEncoder do it. When I define explicitly BCryptPasswordEncoder as an encoder for DaoAuthenticationProvider it calls matches method on BCryptPasswordEncoder (without id strip), but not on DelegatingPasswordEncoder (with id strip).

BCryptPasswordEncoder 不会剥离 {bcrypt} id,但 DelegatingPasswordEncoder 会这样做。当我将 BCryptPasswordEncoder 明确定义为 DaoAuthenticationProvider 的编码器时,它会调用 BCryptPasswordEncoder 上的匹配方法(不带 ID 条),但不会调用 DelegatingPasswordEncoder(带 ID 条)上的方法。

回答by Lin Chen

The best way to identify this problem "Encoded password does not look like BCrypt" is setup a break porint in class org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder. And then check the root cause for the warnning.

识别此问题“编码密码看起来不像 BCrypt”的最佳方法是在org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder类中设置一个中断端口。然后检查警告的根本原因。

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

回答by Faqtt0

use noop in secret for tests.

秘密使用 noop 进行测试。

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