Spring Security 5 : ID "null"에 매핑된 PasswordEncoder가 없습니다.
Spring Boot 1.4.9에서Spring Boot 2.0으로 이행하고 Spring Security 5로 이행하려고 하는데 OAuth 2를 통한 인증을 시도하고 있습니다.하지만 다음 오류가 발생합니다.
java.displaces를 클릭합니다.부정 인수예외:ID "null"에 매핑된 PasswordEncoder가 없습니다.
Spring Security 5 문서를 통해 패스워드의 저장 형식이 변경되었음을 알 수 있습니다.
현재 코드에서는 다음과 같이 암호 인코더 bean을 만들었습니다.
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
그러나 다음과 같은 오류가 발생했습니다.
인코딩된 암호가 BCrypt와 같지 않습니다.
따라서 Spring Security 5 문서에 따라 인코더를 업데이트하여 다음을 수행합니다.
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
이제 데이터베이스에 비밀번호를 볼 수 있게 되면 다음과 같이 저장됩니다.
{bcrypt}$2a$10$LoV/3z36G86x6Gn101aekuz3q9d7yfBp3jFn7dzNN/AL5630FyUQ
첫 번째 오류는 사라졌고 인증을 하려고 하면 다음과 같은 오류가 나타납니다.
java.displaces를 클릭합니다.부정 인수예외:ID "null"에 매핑된 PasswordEncoder가 없습니다.
이 문제를 해결하기 위해 Stackoverflow에서 다음 질문을 모두 시도했습니다.
여기 나와 비슷한 질문이 있지만 답변하지 않습니다.
되어 있기 에 다시 .UserDetailsService
.
Spring security 5 매뉴얼에서는 다음 방법을 사용하여 이 예외를 처리할 수 있도록 권장하고 있습니다.
Password Encoder를 위임하는 중입니다.setDefaultPasswordEncoderForMatches(PasswordEncoder)
이것이 수정책이라면 어디에 두면 좋을까요?PasswordEncoder
콩은 아래와 같이 동작하지 않았습니다.
DelegatingPasswordEncoder def = new DelegatingPasswordEncoder(idForEncode, encoders);
def.setDefaultPasswordEncoderForMatches(passwordEncoder);
My Web Security 클래스
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers(HttpMethod.OPTIONS)
.antMatchers("/api/user/add");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
MyOauth2 설정
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Bean
public DefaultAccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancer())
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("test")
.scopes("read", "write")
.authorities(Roles.ADMIN.name(), Roles.USER.name())
.authorizedGrantTypes("password", "refresh_token")
.secret("secret")
.accessTokenValiditySeconds(1800);
}
}
이 건으로 안내 부탁드립니다.나는 이것을 고치는데 몇 시간이 걸렸지만 고칠 수 없다.
「 」를 하는 경우ClientDetailsServiceConfigurer
새로운 패스워드 스토리지 포맷도 클라이언트비밀번호에 적용해야 합니다.
.secret("{noop}secret")
.password("{noop}password")
보안 설정 파일로 이동합니다.
예를 들어 다음과 같습니다.
auth.inMemoryAuthentication()
.withUser("admin").roles("ADMIN").password("{noop}password");
주로 테스트와 디버깅을 위해 안전한 솔루션이 필요하지 않은 동일한 문제에 직면한 사용자도 메모리 사용자를 구성할 수 있습니다.
이것은 단지 장난삼아 하는 것일 뿐이지 현실세계의 시나리오는 아닙니다.
다음 접근방식은 권장되지 않습니다.
여기서 얻은 거야
WebSecurityConfigurerAdapter
다음을 추가합니다.
@SuppressWarnings("deprecation")
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
여기서 패스워드는 해시되지만 메모리에서는 사용할 수 있습니다.
론, 신, 진, 당, 당, 당, 당, real, of, of, of, of, of, of, of, of, of, of, of, of, of ,PasswordEncoder
BCryptPasswordEncoder
아이디
// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
Spring은 패스워드를 저장할 때마다 bcrypt, scrypt, pbkdf2 등의 부호화된 패스워드에 인코더 프리픽스를 넣어 패스워드를 디코딩할 때 적절한 인코더를 사용할 수 있도록 합니다.인코딩된 비밀번호에 접두사가 없는 경우 defaultPasswordEncoderForMatches를 사용합니다.Defacting Password Encoder.class의 일치 메서드를 보고 작동 방식을 확인할 수 있습니다. 따라서 기본적으로 다음 행으로 default Password Encoder For Matches를 설정해야 합니다.
@Bean(name="myPasswordEncoder")
public PasswordEncoder getPasswordEncoder() {
DelegatingPasswordEncoder delPasswordEncoder= (DelegatingPasswordEncoder)PasswordEncoderFactories.createDelegatingPasswordEncoder();
BCryptPasswordEncoder bcryptPasswordEncoder =new BCryptPasswordEncoder();
delPasswordEncoder.setDefaultPasswordEncoderForMatches(bcryptPasswordEncoder);
return delPasswordEncoder;
}
이 인코더에 Default Password Encoder For Matches를 인증 프로바이더에도 제공해야 합니다.설정 클래스에서 아래 행을 사용하여 이 작업을 수행했습니다.
@Bean
@Autowired
public DaoAuthenticationProvider getDaoAuthenticationProvider(@Qualifier("myPasswordEncoder") PasswordEncoder passwordEncoder, UserDetailsService userDetailsServiceJDBC) {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
daoAuthenticationProvider.setUserDetailsService(userDetailsServiceJDBC);
return daoAuthenticationProvider;
}
이게 누구에게도 도움이 될지 모르겠어.동작하고 있는 Web Security Configr 및 OAuth2 Config 코드는 다음과 같습니다.
OAuth2Config 파일:
package com.crown.AuthenticationServer.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("crown")
.secret("{noop}thisissecret")
.authorizedGrantTypes("refresh_token", "password", "client_credentials")
.scopes("webclient", "mobileclient");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
Web Security Configr:
package com.crown.AuthenticationServer.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
final User.UserBuilder userBuilder = User.builder().passwordEncoder(encoder::encode);
UserDetails user = userBuilder
.username("john.carnell")
.password("password")
.roles("USER")
.build();
UserDetails admin = userBuilder
.username("william.woodward")
.password("password")
.roles("USER","ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
프로젝트 링크: springboot-authorization-server-oauth2
Spring Security Documentation에서 다음 내용을 읽어보실 수 있습니다.DelegatingPasswordEncoder
암호의 일반 형식은 {id}encodedPassword입니다.
따라서 id는 어떤 Password Encoder를 사용해야 하는지 검색하기 위해 사용되는 식별자이며 encoded Password는 선택한 Password Encoder의 원래 인코딩된 암호입니다.ID는 암호의 시작 부분에 있어야 합니다. 시작은 {}, 끝은 {}(으)로 시작합니다.ID를 찾을 수 없는 경우 ID는 null이 됩니다.예를 들어, 다음은 다른 ID를 사용하여 인코딩된 비밀번호 목록입니다.원래 비밀번호는 모두 "password"입니다.
ID의 예는 다음과 같습니다.
{bcrypt}$2a$10$dXJ3SW6G7P50lMkkmwe20cQQubK3.HZWZG3YB1tlRy.fqvM/BG {noop} 비밀번호 {pbkdf2}5d923b44a6d129f3df3e3c8d29412723dcbde72445e8ef6b3b50ffa4dc676dcaWJaSu2IKSn9Z9kM+TPXfOc/9bdYSRN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24Hnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYv7BeL1QxwRpY5Pc=
{sha256}97cde38028ad898ebc02e6908e220e88c62e0699403e941cffff291cfff8410849f27605bc0
데이터베이스에서 사용자 이름과 비밀번호를 가져오는 경우 아래 코드를 사용하여 NoOpPassword 인스턴스를 추가할 수 있습니다.
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(adm).passwordEncoder(NoOpPasswordEncoder.getInstance());
}
여기서 adm은 getPassword() 메서드와 getUsername() 메서드를 가진 프로젝트의 커스텀 사용자 객체입니다.
또, 커스텀 유저 POJO 를 작성하려면 , 유저 상세 인터페이스를 실장해, 그 모든 메서드를 실장할 필요가 있습니다.
이게 도움이 됐으면 좋겠다.
그java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
에러 메시지는 Spring Security 4에서5로 업그레이드 할 때 발생합니다.자세한 설명과 가능한 해결책에 대해서는 이 백등기사를 참조하시기 바랍니다.
Spring Boot 공식 문서에서는 이에 대한 해결책을 제공하고 있습니다.
이 오류를 해결하는 가장 쉬운 방법은 비밀번호가 인코딩된 PasswordEncoder를 명시적으로 제공하는 것으로 전환하는 것입니다.이 문제를 해결하는 가장 쉬운 방법은 현재 비밀번호가 어떻게 저장되어 있는지 파악하여 올바른 Password Encoder를 명시적으로 제공하는 것입니다.
Spring Security 4.2.x에서 마이그레이션하는 경우 NoOp Password Encoder bean을 노출하여 이전 동작으로 되돌릴 수 있습니다.
또는 모든 비밀번호 앞에 올바른 ID를 붙이고 위임 비밀번호 인코더를 계속 사용할 수 있습니다.예를 들어 BCrypt를 사용하는 경우 마이그레이션... 추가 정보
@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserDetailsService userDetailsService;
@Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(NoOpPasswordEncoder.getInstance());
return provider;
}
}
아래 두 개의 주석을 추가하는 것은 해당 문제를 해결했습니다.
@설정 @EnableWebSecurity
에 관하여
인코딩된 암호가 BCrypt와 같지 않습니다.
제 경우 pwd 해시가 strength 4로 생성되었기 때문에 기본 컨스트럭터(10)에 의해 사용되는 BCrypt Password Encoder strength가 일치하지 않았습니다.그래서 나는 힘을 명시적 설정했습니다.
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(4);
}
또한 나의 봄은 보안 버전은 5.1.6항, 완벽하게 BCryptPasswordEncoder와 함께 일하고 있다.
언급URL:https://stackoverflow.com/questions/49654143/spring-security-5-there-is-no-passwordencoder-mapped-for-the-id-null
'source' 카테고리의 다른 글
Closeable 구현 또는 AutoCloseable 구현 (0) | 2022.09.03 |
---|---|
스프링 테스트에서 환경 변수 또는 시스템 속성을 설정하는 방법은 무엇입니까? (0) | 2022.09.03 |
여러 키를 사용하여 맵을 구현하는 방법 (0) | 2022.09.03 |
소품 및 데이터 중복을 방지하려면 어떻게 해야 합니까? (0) | 2022.09.03 |
Java에서의 정적 할당 - 힙, 스택 및 영구 생성 (0) | 2022.09.03 |