스프링부트를 이용한 마이크로서비스 구축론과 프레임워크를 제시해주고 있는 책이다.
그런데 7장을 보면, Authorization 서버를 구축하는 내용을 볼 수 있는데,
책에서 하라는대로 했는데도 불구하고 맨 처음부터 코드가 돌아가지 않는다.
분명히 그대로했는데 또 안된다... 😭
이유인 즉슨, 이 책은 2018년에 출간했는데, 2019년 말에 Spring-cloud-security에서 Authorization Server에 대한 지원 종료를 한다고 언급했기 때문이다.
따라서 문제 해결을 위해 공식 레포를 뒤져봤는데도 SSO (Single Sign On)에 대한 언급 뿐, Authorization Server에 대한 언급은 없다...
따라서 책 내용을 그대로 하다보면, 총 3가지의 문제 때문에 서버가 정상 동작하지 않는다
3가지 문제점은 다음과 같다.
1. Annotation이 들어먹질 않는다.
@EnableAuthorizationServer
@EnableResourceServer
제시된 의존성을 추가했는데 위 두 Annotation에 대해 Not Found Error를 내뿜는걸 볼 수 있다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
을 추가하면 어노테이션을 찾을 수 없다는 문제를 해결할 수 있다.
다음은 Full authentication is required to access this resource
에 대한 문제 해결 방법이다.
2. Spring Security 5.x로의 변화
Spring Security의 5.x대로의 변화로 Password Encoder 방식이 변경됐다. 그래서 백날 시도해봐야 Full Authentication 이 필요하다고 뜨더라,,
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("eagleeye")
.secret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("thisissecret"))
.authorizedGrantTypes("refresh_token","password","client_credentials")
.scopes("webclient","mobileclient");
}
라면 다음과 같이 수정한다.
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("eagleeye")
.secret("{noop}thisissecret")
.authorizedGrantTypes("refresh_token","password","client_credentials")
.scopes("webclient","mobileclient");
}
또 아래코드를
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.passwordEncoder(encoder)
.withUser("admin1234").password("password1").roles("USER","ADMIN")
.and()
.withUser("test1234").password("password1").roles("USER");
}
다음과 같이 고친다.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin1234").password("{noop}password1").roles("USER","ADMIN")
.and()
.withUser("test1234").password("{noop}password1").roles("USER");
}
위 코드의 경우 NoOpPasswordEncoder 방식으로 해결하는 경우이다.
실제 코드의 경우 InMemory방식이 아니라 DB 연동방식의 경우가 대부분일 것이고 Bcrpyt를 사용할 것이다...
아무튼 문제를 해결하고 이제 되나 싶었더니
그럼에도 불구하고 또 안된다. 😂
3. 토큰을 요청하는 경로가 잘못됨
책에서는 분명히 http://localhost:port/auth/oauth/token/
에 요청을 하라고 했는데, 실제 경로 요청은 http://localhost:port/oauth/token
이다.
잘못된 경로로 계속 요청을 하니, 들어먹을리가 있나...
아무튼 위와 같은 모든 문제를 해결하고 나면
올바르게 토큰이 생성되는 것을 볼 수 있다.
시간을 생각보다 많이 썼다..
그래도 뭔가 책에 있는 내용이 잘못됨을 지적하고, 해결법을 제시해서 뿌듯하긴하다.
개정판이 얼른 나왔으면 좋겠다 ㅎ