OAuth2 액세스 토큰 전파
This commit is contained in:
@@ -174,6 +174,15 @@ HOW TO RUN
|
||||
|
||||
-- 액세스 토큰으로 사용자 정보 조회
|
||||
[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 static final String CORRELATION_ID = "assu-correlation-id";
|
||||
|
||||
private String correlationId = new String();
|
||||
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||
|
||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||
|
||||
public String getCorrelationId() {
|
||||
return correlationId;
|
||||
public static String getCorrelationId() {
|
||||
return correlationId.get();
|
||||
}
|
||||
|
||||
public void setCorrelationId(String correlationId) {
|
||||
this.correlationId = correlationId;
|
||||
public static void setCorrelationId(String cid) {
|
||||
correlationId.set(cid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth.boot</groupId>
|
||||
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
@@ -1,17 +1,55 @@
|
||||
package com.assu.cloud.eventservice;
|
||||
|
||||
import com.assu.cloud.eventservice.utils.CustomContextInterceptor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
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.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
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
@EnableResourceServer
|
||||
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) {
|
||||
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}")
|
||||
private String yourName;
|
||||
|
||||
@Value("${service.id.zuul}")
|
||||
private String serviceIdZuul;
|
||||
|
||||
public String getYourName() {
|
||||
return yourName;
|
||||
}
|
||||
|
||||
public String getServiceIdZuul() {
|
||||
return serviceIdZuul;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.config.CustomConfig;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -13,10 +14,12 @@ public class EventController {
|
||||
|
||||
private final CustomConfig customConfig;
|
||||
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.memberFeignClient = memberFeignClient;
|
||||
this.memberRestTemplateClient = memberRestTemplateClient;
|
||||
}
|
||||
|
||||
@GetMapping(value = "name/{nick}")
|
||||
@@ -45,4 +48,9 @@ public class EventController {
|
||||
public String gift(@PathVariable("name") String 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 static final String CORRELATION_ID = "assu-correlation-id";
|
||||
|
||||
private String correlationId = new String();
|
||||
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||
|
||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||
|
||||
public String getCorrelationId() {
|
||||
return correlationId;
|
||||
public static String getCorrelationId() {
|
||||
return correlationId.get();
|
||||
}
|
||||
|
||||
public void setCorrelationId(String correlationId) {
|
||||
this.correlationId = correlationId;
|
||||
public static void setCorrelationId(String cid) {
|
||||
correlationId.set(cid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Component
|
||||
public class EventRestTemplateClient {
|
||||
|
||||
RestTemplate restTemplate;
|
||||
CustomConfig customConfig;
|
||||
private final RestTemplate restTemplate;
|
||||
private final CustomConfig customConfig;
|
||||
|
||||
public EventRestTemplateClient(RestTemplate restTemplate, CustomConfig customConfig) {
|
||||
this.restTemplate = restTemplate;
|
||||
|
||||
@@ -40,4 +40,12 @@ public class MemberController {
|
||||
public String member(@PathVariable("name") String name) {
|
||||
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 static final String CORRELATION_ID = "assu-correlation-id";
|
||||
|
||||
private String correlationId = new String();
|
||||
private static final ThreadLocal<String> correlationId = new ThreadLocal<>();
|
||||
|
||||
// 그 외 필요한 항목 넣을 수 있음 (인증 토큰 등...)
|
||||
|
||||
public String getCorrelationId() {
|
||||
return correlationId;
|
||||
public static String getCorrelationId() {
|
||||
return correlationId.get();
|
||||
}
|
||||
|
||||
public void setCorrelationId(String correlationId) {
|
||||
this.correlationId = correlationId;
|
||||
public static void setCorrelationId(String cid) {
|
||||
correlationId.set(cid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import org.springframework.stereotype.Component;
|
||||
public class CustomContext {
|
||||
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() {
|
||||
return correlationId;
|
||||
public static String getCorrelationId() {
|
||||
return correlationId.get();
|
||||
}
|
||||
|
||||
public void setCorrelationId(String correlationId) {
|
||||
this.correlationId = correlationId;
|
||||
public static void setCorrelationId(String cid) {
|
||||
correlationId.set(cid);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user