OAuth2 액세스 토큰 전파
This commit is contained in:
@@ -174,6 +174,15 @@ HOW TO RUN
|
|||||||
|
|
||||||
-- 액세스 토큰으로 사용자 정보 조회
|
-- 액세스 토큰으로 사용자 정보 조회
|
||||||
[GET] http://localhost:8901/auth/user
|
[GET] http://localhost:8901/auth/user
|
||||||
|
|
||||||
|
-- OAuth2 로 회원 서비스 보호 후 API 호출
|
||||||
|
[GET] http://localhost:8090/member/name/rinda
|
||||||
|
|
||||||
|
-- 권한 있는 사용자(assuAdmin) 의 액세스 토큰과 함께 PUT 메서드 API 호출
|
||||||
|
[PUT] http://localhost:8090/member/rinda
|
||||||
|
|
||||||
|
-- oauth2 전파 (이벤트 서비스에서 회원서비스 호출)
|
||||||
|
[GET] http://localhost:5555/api/evt/event/userInfo/rinda
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import org.springframework.stereotype.Component;
|
|||||||
public class CustomContext {
|
public class CustomContext {
|
||||||
public static final String CORRELATION_ID = "assu-correlation-id";
|
public static final String CORRELATION_ID = "assu-correlation-id";
|
||||||
|
|
||||||
private String correlationId = new String();
|
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||||
|
|
||||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||||
|
|
||||||
public String getCorrelationId() {
|
public static String getCorrelationId() {
|
||||||
return correlationId;
|
return correlationId.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCorrelationId(String correlationId) {
|
public static void setCorrelationId(String cid) {
|
||||||
this.correlationId = correlationId;
|
correlationId.set(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,11 @@
|
|||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security.oauth.boot</groupId>
|
||||||
|
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|||||||
@@ -1,17 +1,55 @@
|
|||||||
package com.assu.cloud.eventservice;
|
package com.assu.cloud.eventservice;
|
||||||
|
|
||||||
|
import com.assu.cloud.eventservice.utils.CustomContextInterceptor;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateFactory;
|
||||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||||
|
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@EnableEurekaClient
|
@EnableEurekaClient
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
|
@EnableResourceServer
|
||||||
public class EventServiceApplication {
|
public class EventServiceApplication {
|
||||||
|
|
||||||
|
//@LoadBalanced
|
||||||
|
@Bean
|
||||||
|
public OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
|
||||||
|
List interceptors = factory.getUserInfoRestTemplate().getInterceptors();
|
||||||
|
|
||||||
|
if (interceptors == null) {
|
||||||
|
factory.getUserInfoRestTemplate().setInterceptors(Collections.singletonList(new CustomContextInterceptor()));
|
||||||
|
} else {
|
||||||
|
interceptors.add(new CustomContextInterceptor());
|
||||||
|
factory.getUserInfoRestTemplate().setInterceptors(interceptors);
|
||||||
|
}
|
||||||
|
return factory.getUserInfoRestTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*@LoadBalanced // 스프링 클라우드가 리본이 지원하는 RestTemplate 클래스 생성하도록 지시
|
||||||
|
@Bean
|
||||||
|
public RestTemplate getRestTemplate() {
|
||||||
|
// return new RestTemplate();
|
||||||
|
RestTemplate template = new RestTemplate();
|
||||||
|
List interceptors = template.getInterceptors();
|
||||||
|
|
||||||
|
if (interceptors == null) {
|
||||||
|
template.setInterceptors(Collections.singletonList(new CustomContextInterceptor()));
|
||||||
|
} else {
|
||||||
|
interceptors.add(new CustomContextInterceptor());
|
||||||
|
template.setInterceptors(interceptors);
|
||||||
|
}
|
||||||
|
return template;
|
||||||
|
}*/
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(EventServiceApplication.class, args);
|
SpringApplication.run(EventServiceApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.assu.cloud.eventservice.client;
|
||||||
|
|
||||||
|
import com.assu.cloud.eventservice.config.CustomConfig;
|
||||||
|
import com.assu.cloud.eventservice.utils.CustomContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MemberRestTemplateClient {
|
||||||
|
|
||||||
|
private final OAuth2RestTemplate restTemplate;
|
||||||
|
private final CustomConfig customConfig;
|
||||||
|
|
||||||
|
public MemberRestTemplateClient(OAuth2RestTemplate restTemplate, CustomConfig customConfig) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
this.customConfig = customConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
String URL_PREFIX = "/api/mb/member/"; // 회원 서비스의 주울 라우팅경로와 회원 클래스 주소
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MemberRestTemplateClient.class);
|
||||||
|
|
||||||
|
public String userInfo(String name) {
|
||||||
|
logger.debug("===== In Member Service.userInfo: {}", CustomContext.getCorrelationId());
|
||||||
|
|
||||||
|
ResponseEntity<String> restExchange =
|
||||||
|
restTemplate.exchange(
|
||||||
|
//"http://" + customConfig.getServiceIdZuul() + URL_PREFIX + "userInfo/{name}", // http://localhost:5555/api/mb/member/userInfo/rinda
|
||||||
|
"http://localhost:5555/api/mb/member/userInfo/{name}", // http://localhost:5555/api/mb/member/userInfo/rinda
|
||||||
|
HttpMethod.GET,
|
||||||
|
null, String.class, name
|
||||||
|
);
|
||||||
|
|
||||||
|
return restExchange.getBody();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,14 @@ public class CustomConfig {
|
|||||||
@Value("${your.name}")
|
@Value("${your.name}")
|
||||||
private String yourName;
|
private String yourName;
|
||||||
|
|
||||||
|
@Value("${service.id.zuul}")
|
||||||
|
private String serviceIdZuul;
|
||||||
|
|
||||||
public String getYourName() {
|
public String getYourName() {
|
||||||
return yourName;
|
return yourName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getServiceIdZuul() {
|
||||||
|
return serviceIdZuul;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.assu.cloud.eventservice.controller;
|
package com.assu.cloud.eventservice.controller;
|
||||||
|
|
||||||
|
import com.assu.cloud.eventservice.client.MemberRestTemplateClient;
|
||||||
import com.assu.cloud.eventservice.client.MemberFeignClient;
|
import com.assu.cloud.eventservice.client.MemberFeignClient;
|
||||||
import com.assu.cloud.eventservice.config.CustomConfig;
|
import com.assu.cloud.eventservice.config.CustomConfig;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@@ -13,10 +14,12 @@ public class EventController {
|
|||||||
|
|
||||||
private final CustomConfig customConfig;
|
private final CustomConfig customConfig;
|
||||||
private final MemberFeignClient memberFeignClient;
|
private final MemberFeignClient memberFeignClient;
|
||||||
|
private final MemberRestTemplateClient memberRestTemplateClient;
|
||||||
|
|
||||||
public EventController(CustomConfig customConfig, MemberFeignClient memberFeignClient) {
|
public EventController(CustomConfig customConfig, MemberFeignClient memberFeignClient, MemberRestTemplateClient memberRestTemplateClient) {
|
||||||
this.customConfig = customConfig;
|
this.customConfig = customConfig;
|
||||||
this.memberFeignClient = memberFeignClient;
|
this.memberFeignClient = memberFeignClient;
|
||||||
|
this.memberRestTemplateClient = memberRestTemplateClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "name/{nick}")
|
@GetMapping(value = "name/{nick}")
|
||||||
@@ -45,4 +48,9 @@ public class EventController {
|
|||||||
public String gift(@PathVariable("name") String gift) {
|
public String gift(@PathVariable("name") String gift) {
|
||||||
return "[EVENT] Gift is " + gift;
|
return "[EVENT] Gift is " + gift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("userInfo/{name}")
|
||||||
|
public String userInfo(@PathVariable("name") String name) {
|
||||||
|
return "[EVENT-MEMBER] " + memberRestTemplateClient.userInfo(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.assu.cloud.eventservice.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 접근 제어 규칙 정의
|
||||||
|
* 인증된 사용자는 모든 서비스에 접근 가능하거나,
|
||||||
|
* 특정 역할을 가진 애플리케이션만 PUT URL 로 접근하는 등 세밀하기 정의 가능
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
|
||||||
|
/**
|
||||||
|
* 모든 접근 규칙을 재정의한 configure()
|
||||||
|
* @param http
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configure(HttpSecurity http) throws Exception {
|
||||||
|
// 매서드로 전달된 HttpSecurity 객체로 모든 접근 규칙 구성
|
||||||
|
|
||||||
|
// 회원 서비스의 모든 URL 에 대해 인증된 사용자만 접근하도록 제한
|
||||||
|
//http.authorizeRequests().anyRequest().authenticated();
|
||||||
|
|
||||||
|
http.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.PUT, "/member/**") // 쉼표로 구분하여 엔드 포인트 목록 받음
|
||||||
|
.hasRole("ADMIN") // ADMIN 권한을 가진 사용자만 PUT 호출 가능
|
||||||
|
.anyRequest() // 서비스의 모든 엔드포인트도 인증된 사용자만 접근 가능하도록 설정
|
||||||
|
.authenticated();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,15 +10,15 @@ import org.springframework.stereotype.Component;
|
|||||||
public class CustomContext {
|
public class CustomContext {
|
||||||
public static final String CORRELATION_ID = "assu-correlation-id";
|
public static final String CORRELATION_ID = "assu-correlation-id";
|
||||||
|
|
||||||
private String correlationId = new String();
|
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||||
|
|
||||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||||
|
|
||||||
public String getCorrelationId() {
|
public static String getCorrelationId() {
|
||||||
return correlationId;
|
return correlationId.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCorrelationId(String correlationId) {
|
public static void setCorrelationId(String cid) {
|
||||||
this.correlationId = correlationId;
|
correlationId.set(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
@Component
|
@Component
|
||||||
public class EventRestTemplateClient {
|
public class EventRestTemplateClient {
|
||||||
|
|
||||||
RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
CustomConfig customConfig;
|
private final CustomConfig customConfig;
|
||||||
|
|
||||||
public EventRestTemplateClient(RestTemplate restTemplate, CustomConfig customConfig) {
|
public EventRestTemplateClient(RestTemplate restTemplate, CustomConfig customConfig) {
|
||||||
this.restTemplate = restTemplate;
|
this.restTemplate = restTemplate;
|
||||||
|
|||||||
@@ -40,4 +40,12 @@ public class MemberController {
|
|||||||
public String member(@PathVariable("name") String name) {
|
public String member(@PathVariable("name") String name) {
|
||||||
return "[MEMBER-DELETE] " + name + " is deleted.";
|
return "[MEMBER-DELETE] " + name + " is deleted.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 이벤트 서비스에서 OAuth2 로 호출 테스트
|
||||||
|
*/
|
||||||
|
@GetMapping("userInfo/{name}")
|
||||||
|
public String userInfo(@PathVariable("name") String name) {
|
||||||
|
return "[MEMBER] " + name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import org.springframework.stereotype.Component;
|
|||||||
public class CustomContext {
|
public class CustomContext {
|
||||||
public static final String CORRELATION_ID = "assu-correlation-id";
|
public static final String CORRELATION_ID = "assu-correlation-id";
|
||||||
|
|
||||||
private String correlationId = new String();
|
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||||
|
|
||||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||||
|
|
||||||
public String getCorrelationId() {
|
public static String getCorrelationId() {
|
||||||
return correlationId;
|
return correlationId.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCorrelationId(String correlationId) {
|
public static void setCorrelationId(String cid) {
|
||||||
this.correlationId = correlationId;
|
correlationId.set(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import org.springframework.stereotype.Component;
|
|||||||
public class CustomContext {
|
public class CustomContext {
|
||||||
public static final String CORRELATION_ID = "assu-correlation-id";
|
public static final String CORRELATION_ID = "assu-correlation-id";
|
||||||
|
|
||||||
private String correlationId = new String();
|
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||||
|
|
||||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||||
|
|
||||||
public String getCorrelationId() {
|
public static String getCorrelationId() {
|
||||||
return correlationId;
|
return correlationId.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCorrelationId(String correlationId) {
|
public static void setCorrelationId(String cid) {
|
||||||
this.correlationId = correlationId;
|
correlationId.set(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user