인코딩된 암호가 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보다 큽니다.
BCryptPasswordEncoder는 raw 비밀번호를 인코딩된 비밀번호와 일치하지 않을 때 이 경고를 표시합니다.
해시된 비밀번호는 "$20b" 또는 "$2y"일 수 있습니다.
Spring Security에는 항상 $2a를 찾는 정규식이 있는 버그가 있습니다.디버깅 포인트를 에 배치합니다.matches()
에서 기능하다BCryptPasswordEncoder.class
.
고객 비밀이 암호화되어 있는지 다시 한 번 확인해 주시겠어요?
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.inMemory()
.withClient(clientId)
.secret(passwordEncoder.encode(clientSecret))
.authorizedGrantTypes(grantType)
.scopes(scopeRead, scopeWrite)
.resourceIds(resourceIds);
}
Password Encoder는 다음과 같이 설정해야 합니다.
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
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"));
}
오늘부로 Spring Boot 2.1.7을 사용하고 있습니다.릴리스, 아직 이 문제가 발생하고 있습니다.20억 달러나 20만 달러부터 시작하는 해쉬를 주는 온라인 도구를 사용했는데, 스프링의 경우BCryptPasswordEncoder
에서는 다음 사항이 허용되지 않습니다.
public class BCryptPasswordEncoder implements PasswordEncoder {
private Pattern BCRYPT_PATTERN = Pattern
.compile("\\A\\$2a?\\$\\d\\d\\$[./0-9A-Za-z]{53}");
...
솔루션: 사용BCryptPasswordEncoder
class를 사용하여 비밀번호를 인코딩합니다.
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");
}
[ Update ]필드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);
이 문제를 특정하는 가장 좋은 방법은 class org.springframework에 break porint를 설정하는 것입니다.security.security.bcrypt.BCrypt Password Encoder.그리고 경고의 근본 원인을 확인합니다.
if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
logger.warn("Encoded password does not look like BCrypt");
return false;
}
저만의 비슷한 시나리오에서는 그냥 이렇게 암호를 인코딩했습니다.passwordEncoder().encode("password")
raw String 대신"password"
:
authenticationManagerBuilder
.inMemoryAuthentication()
.withUser("user")
// Just changed here
.password(passwordEncoder().encode("password"))
.roles("USER");
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
BCryptPasswordEncoder는 {bcrypt} ID를 제거하지 않지만 DelegingPasswordEncoder가 제거합니다.BCrypt Password Encoder를 Dao Authentication Provider의 인코더로 명시적으로 정의하면 BCrypt Password Encoder(ID 스트립 없음)에서는 matches 메서드를 호출하지만 Deleging Password Encoder(ID 스트립 있음)에서는 호출하지 않습니다.
동일한 오류가 발생했는데, 이는 암호 열의 데이터 유형 때문이었습니다. 이 열은 길이 공백(CARTER)이므로 VARCHAR 데이터 유형을 사용하고 있는지 확인하거나 암호 열의 길이를 60으로 변경하십시오.
Spring Security 5에서는 기본 인코더는 Deleganting Password Encoder로 비밀번호 저장 형식이 필요합니다.
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
마찬가지로 InMemory 비밀번호를 부호화해야 한다는 문제도 있었습니다.이는 Spring Security에서 로그인을 클릭하면 추출된 비밀번호를 HTTP Basic Auth 헤더에서 가져와 자동으로 해시하고 UserDetails 객체의 해시된 비밀번호와 비교하기 때문입니다.양쪽이 일치하면 사용자는 정상적으로 인증됩니다.그렇지 않으면 이 에러가 발생합니다.
예를들면,
Password = " InMemory = "123"
passwordEncoder.encode("123")
참조: 링크
하시는 메서드가 .UserDetails loadUserByUsername(String username)
한 " " " 를 합니다.UserDetail
건 。 이 됩니다.반환된 오브젝트 null/returned object.
- 비밀번호 직전에 "{bcrypt}"를 추가하고 그에 따라 앱을 구성하지 않은 경우 이 오류가 발생합니다.이것을 삭제하는 것을 검토해 주세요.
- 그래도 해결되지 않으면 사용자 비밀번호의 열 길이를 60(처음에 {bcryt}을(를) 추가한 경우 68)로 설정해 주세요!
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);
에서 이 수 .SecurityConfig
@Bean
public DaoAuthenticationProvider getAuthenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(customDetailsService);
authenticationProvider.setPasswordEncoder(encoder());
return authenticationProvider;
}
비밀리에 noop을 테스트에 사용합니다.
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("angular")
.secret("{noop}@ngular0")
.scopes("read", "write")
.authorizedGrantTypes("password")
.accessTokenValiditySeconds(1800);
}
CXPW3XT2vXwBZk9m 등 60글자 이상의 긴 비밀번호를 사용하여 이 오류 메시지를 삭제했습니다.YZ5eCrKPM8kXJC6bwJQjtGq2NQRYQPzvqTwYz8JvWhWD5KLRUHHHammBNV3tkkyA4u
UserDetails 엔티티는 부호화된 비밀번호를 반환해야 합니다.이것은, 실장에 의해서 다릅니다.
class MyUserDetails: UserDetails {
//...
override fun getPassword(): String {
return passwordEncoder().encode("aPassword")
}
private fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}
GL
문제는 패스워드의 빈 공간입니다.
사용자 지정 UserDetailsService 클래스에서 돌아오는 동안 암호를 트리밍해 보십시오.
는 bcrypt에서 시작하는 .$2y
로로 합니다.$2a
ㅇㅇㅇ.$2y$12$0Evlz//oO
로로 합니다.$2a$12$0Evlz//oO
나한테는 효과가 있었어요
스프링 부트에서의 유스케이스와는 다른 것을 고려하여 위의 모든 솔루션을 사용해 보았습니다.내 경우 DBMS를 MySQL에서 Postgre로 전환했습니다.MySQL의 경우 로그인/로그아웃 기능이 완벽하게 작동하여 SQL과 앱은 정상적으로 작동하였습니다.그러나 Postgres로 전환했을 때 로그인 기능에 이 에러가 표시되기 시작했습니다.pgAdmin에서 BCrypt 비밀번호에 여분의 공간이 있다는 것을 알게 되었습니다.수동으로 삭제하려고 했지만 매번 변경 내용이 자동으로 롤백되었습니다.
그러다가 어디선가 읽었는데, BCrypt 암호화 텍스트 길이는 고정되어 있습니다. 즉, 60글자입니다.하지만 Postgres의 비밀번호 필드는 80자였습니다.필드 길이를 80자에서 60자로 간단히 변경했습니다.GUI를 사용하거나 CLI에서 ALTER TABLE 명령을 사용하여 원하는 대로 실행할 수 있습니다.
다음 코드로 이 오류를 제거합니다.
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodedPassword = passwordEncoder.encode(CLIENT_SECRET);
configurer
.inMemory()
.withClient(CLIENT_ID)
.secret(encodedPassword)
.authorizedGrantTypes(GRANT_TYPE)
.scopes(SCOPE_READ, SCOPE_WRITE)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS);
}
그래서 그 비밀을 부호화할 필요가 있다.
Spring Security 5 OAuth 2 Server는 이렇게 수정했습니다.
@Bean
public PasswordEncoder delegatingPasswordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders);
passwordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());
return passwordEncoder;
}
lol spring rrr 이거 먹어봐
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
저도 같은 문제에 직면해 있었습니다.
제 경우 테이블의 컬럼 길이가 50자밖에 되지 않아 나중에 위의 제안과 같이 컬럼 길이를 100으로 수정하면 효과가 있었습니다.
ALTER TABLE `users`
CHANGE COLUMN `password` `password` VARCHAR(100) NOT NULL AFTER `enabled`;
언급URL : https://stackoverflow.com/questions/49582971/encoded-password-does-not-look-like-bcrypt
'sourcecode' 카테고리의 다른 글
AngularJS + 돛.js (0) | 2023.02.23 |
---|---|
스프링 부트 서버를 시작할 수 없습니다. (0) | 2023.02.23 |
utf-8의 python jsonify 사전 (0) | 2023.02.23 |
경고 .ts 파일을 삭제하는 방법은 TypeScript 컴파일의 일부이지만 사용되지 않습니다. (0) | 2023.02.18 |
wp_filter는 태그에 영향을 주지 않습니다.</h2 ><p> 테마 <code> functions.php </code> 파일에 다음 필터를 추가했습니다.</p><pre> <code> 함수 변경_the_code() { 'My modified title'을 반환한다.}add_filter wp_filter', '.. (0) | 2023.02.15 |