OAuth2 인증 서버에 클라이언트 애플리케이션 등록
This commit is contained in:
@@ -47,15 +47,15 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-security</artifactId>
|
||||
</dependency>
|
||||
<!-- springboot 2 에선 spring-security-oauth2 기능이 핵심 spring security 로 포팅되어 별도 추가 필요 없음 -->
|
||||
<!--<dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-oauth2</artifactId>
|
||||
</dependency>-->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -17,22 +17,19 @@ import java.util.Map;
|
||||
@EnableResourceServer
|
||||
@EnableAuthorizationServer // 이 서비스가 OAuth2 인증 서버가 될 것이라고 스프링 클라우드에 알림
|
||||
public class AuthServiceApplication {
|
||||
|
||||
/**
|
||||
* 사용자 정보 조회 시 사용
|
||||
* OAuth2 로 보호되는 서비스에 접근하려고 할 때 사용
|
||||
* 보호 서비스로 호출되어 OAuth2 액세스 토큰의 유효성을 검증하고 보호 서비스에 접근하는 사용자 역할 조회
|
||||
*/
|
||||
@RequestMapping(value = { "/user" }, produces = "application/json")
|
||||
@RequestMapping(value = { "/user" }, produces = "application/json") // /auth/user 로 매핑
|
||||
public Map<String, Object> user(OAuth2Authentication user) {
|
||||
Map<String, Object> userInfo = new HashMap<>();
|
||||
userInfo.put("user", user.getUserAuthentication().getPrincipal());
|
||||
userInfo.put("authorities", AuthorityUtils.authorityListToSet(user.getUserAuthentication().getAuthorities()));
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AuthServiceApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.assu.cloud.authservice.security;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
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;
|
||||
|
||||
/**
|
||||
* OAuth2 인증 서버에 등록될 애플리케이션 정의
|
||||
* AuthorizationServerConfigurerAdapter: 스프링 시큐리티 핵심부, 핵심 인증 및 인가 기능 수행하는 기본 메커니즘 제공
|
||||
*/
|
||||
@Configuration
|
||||
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
public OAuth2Config(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증 서버에 등록될 클라이언트 정의
|
||||
* 즉, OAuth2 서비스로 보호되는 서비스에 접근할 수 있는 클라이언트 애플리케이션 등록
|
||||
*/
|
||||
@Override
|
||||
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
|
||||
clients.inMemory() // 애플리케이션 정보를 위한 저장소 (인메모리 / JDBC)
|
||||
.withClient("assuapp") // assuapp 애플리케이션이 토큰을 받기 위해 인증 서버 호출 시 제시할 시크릿과 애플리케이션명
|
||||
.secret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("12345"))
|
||||
.authorizedGrantTypes("refresh_token", "password", "client_credentials") // OAuth2 에서 지원하는 인가 그랜트 타입, 여기선 패스워드/클라이언트 자격증명 그랜트타입
|
||||
.scopes("webclient", "mobileclient"); // 토큰 요청 시 애플리케이션의 수행 경계 정의
|
||||
}
|
||||
|
||||
/**
|
||||
* AuthorizationServerConfigurerAdapter 안에서 사용될 여러 컴포넌트 정의
|
||||
* 여기선 스프링에 기본 인증 관리자와 사용자 상세 서비스를 이용한다고 선언
|
||||
*/
|
||||
@Override
|
||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
|
||||
endpoints.authenticationManager(authenticationManager)
|
||||
.userDetailsService(userDetailsService);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.assu.cloud.authservice.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;
|
||||
|
||||
@Configuration
|
||||
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
|
||||
@Bean
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.assu.cloud.authservice.utils;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 서비스가 쉽게 액세스할 수 있는 HTTP 헤더를 만들어 저장하는 클래스
|
||||
* HTTP 요청에서 추출한 값을 보관하는 POJO
|
||||
*/
|
||||
@Component
|
||||
public class CustomContext {
|
||||
public static final String CORRELATION_ID = "assu-correlation-id";
|
||||
|
||||
private String correlationId = new String();
|
||||
|
||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||
|
||||
public String getCorrelationId() {
|
||||
return correlationId;
|
||||
}
|
||||
|
||||
public void setCorrelationId(String correlationId) {
|
||||
this.correlationId = correlationId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.assu.cloud.authservice.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 유입되는 HTTP 요청을 가로채서 필요한 헤더값을 CustomContext 에 매핑
|
||||
*
|
||||
* REST 서비스에 대한 모든 HTTP 요청을 가로채서 컨텍스트 정보(상관관계 ID 등)를 추출해 CustomContext 클래스에 매핑하는 HTTP 서블릿 필터
|
||||
* REST 서비스 호출 시 코드에서 CustomContext 액세스가 필요할 때마다 ThreadLocal 변수에서 검색해 읽어올 수 있음
|
||||
*/
|
||||
@Component
|
||||
public class CustomContextFilter implements Filter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomContextFilter.class);
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
|
||||
|
||||
// HTTP 호출 헤더에서 상관관계 ID 를 검색하여 CustomContextHolder 의 CustomContext 클래스에 설정
|
||||
CustomContextHolder.getContext().setCorrelationId(httpServletRequest.getHeader(CustomContext.CORRELATION_ID));
|
||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||
|
||||
logger.debug("상관관계 ID {} 로 실행된 동적 라우팅", CustomContextHolder.getContext().getCorrelationId());
|
||||
|
||||
filterChain.doFilter(httpServletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.assu.cloud.authservice.utils;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* ThreadLocal 저장소에 CustomContext 를 저장하는 클래스
|
||||
* * ThreadLocal 변수: 사용자 요청을 처리하는 해당 스레드에서 호출되는 모든 메서드에서 액세스 가능한 변수
|
||||
*
|
||||
* CustomContext 가 ThreadLocal 저장소에 저장되면 요청으로 실행된 모든 코드에서 CustomContextHolder 의 CustomContext 객체 사용 가능
|
||||
*/
|
||||
public class CustomContextHolder {
|
||||
|
||||
/** 정적 ThreadLocal 변수에 저장되는 CustomContext */
|
||||
private static final ThreadLocal<CustomContext> customContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* CustomContext 객체를 사용하기 위해 조회해오는 메서드
|
||||
*/
|
||||
public static final CustomContext getContext() {
|
||||
CustomContext ctx = customContext.get();
|
||||
|
||||
if (ctx == null) {
|
||||
ctx = createEmptyContext();
|
||||
customContext.set(ctx);
|
||||
}
|
||||
return customContext.get();
|
||||
}
|
||||
|
||||
public static final void setContext(CustomContext ctx) {
|
||||
Assert.notNull(ctx, "customcontxt is null.");
|
||||
customContext.set(ctx);
|
||||
}
|
||||
|
||||
public static final CustomContext createEmptyContext() {
|
||||
return new CustomContext();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.assu.cloud.authservice.utils;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* RestTemplate 인스턴스에서 실행되는 모든 HTTP 기반 서비스 발신 요청에 상관관계 ID 삽입
|
||||
*/
|
||||
public class CustomContextInterceptor implements ClientHttpRequestInterceptor {
|
||||
/**
|
||||
* RestTemplate 로 실제 HTTP 서비스 호출 전 intercept 메서드 호출
|
||||
*/
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
|
||||
HttpHeaders headers = httpRequest.getHeaders();
|
||||
|
||||
headers.add(CustomContext.CORRELATION_ID, CustomContextHolder.getContext().getCorrelationId());
|
||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||
|
||||
return clientHttpRequestExecution.execute(httpRequest, bytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user