-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from mainmethod0126/lets-try-using-the-grpc-ja…
…va-library Lets try using the grpc java library
- Loading branch information
Showing
5 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# 일렉트론의 main 프로세스, renderer 프로세스, preload 스크립트 | ||
|
||
## 프로레스 모델 분리 | ||
|
||
- 크게 **main 프로세스**와 **renderer 프로세스** 두 가지 유형의 프로세스가 존재 | ||
|
||
### Main | ||
|
||
- 일렉트론 앱에는 필수적으로 **단일 main 프로세스**가 존재함 | ||
- 모든 Node.js API 를 사용할 수 있음 | ||
- `BrowserWindow` 모듈을 사용해 window 를 만들고 관리하는게 주 목적 | ||
- **BrowserWindow 인스턴스**가 제거되면 해당 renderer 프로세스도 종료된다 | ||
- `app` 모듈을 통해서 어플리케이션의 생명 주기를 제어한다 | ||
|
||
### Renderer | ||
|
||
- `renderer 프로세스`는 웹 컨텐츠를 렌더링하는 역할을 한다 | ||
- 일렉트론 앱은 각 `BrowserWindow`에 대해 **별도의 renderer 프로세스를 생성** | ||
- 보안 이유로 `Node.js` 를 바로 사용할 수 없다 | ||
|
||
### Preload 스크립트 | ||
|
||
- 웹 컨텐츠가 로드되기 전에 렌더러 프로세스에서 실행되는 코드가 포함되어 있다 | ||
- `BrowserWindow 생성자`의 `webPreferences` 옵션을 통해 main 프로세스에 preload 스크립트를 연결할 수 있다 | ||
- `preload 스크립트`는 **전역 window 인터페이스**를 **renderer와 공유**한다 | ||
- `contextIsolation 기본값` 때문에 preload 스크립트에서 window로 변수를 직접 연결할 수 없다 | ||
- `컨텍스트 격리(Context Isolation)`는 preload 스크립트와 일렉트론의 내부 로직이 webContents에 로드된 웹 사이트에 별도의 컨텍스트에서 실행되도록 하는 기능이다 | ||
- 웹 사이트가 일렉트론 내부 또는 preload 스크립트에 접근하지 못하도록 하기 때문에 보안 목적으로 중요하다 | ||
- 컨텍스트 격리를 통해 preload 스크립트 내 권한을 가진 API가 웹 컨텐츠 코드로 유출되지 않도록 한다. | ||
|
||
--- | ||
|
||
## 프로세스 간 통신 | ||
|
||
- 프로세스 간 통신을 위해 **IPC(Inter-Process Communication)**를 사용한다 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# grpc-java 라이브러리를 사용해보자 | ||
|
||
일단 grpc 용어좀 짚고가자 | ||
|
||
## 채널 channel | ||
|
||
- **네트워크 연결 관리** : 클라이언트와 서버간의 연결 | ||
- **보안** : TLS/SSL 을 통한 보안 통신 가능 | ||
- **상태 모니터링** : 채널은 서버 연결 상태(예: IDLE, CONNECTING, READY, TRANSIENT_FAILURE, SHUTDOWN)를 관리하고, 클라이언트가 이 상태를 추적할 수 있게 해줌 | ||
|
||
### 채널의 생성과 관리 | ||
|
||
채널은 한번 생성하면 재사용하는게 일반적임, | ||
**재사용도 다 하고 이제 쓸일 없으면 닫아야함** | ||
|
||
|
||
채널의 생성 | ||
```java | ||
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051) | ||
.usePlaintext() // TLS를 적용하려면 .useTransportSecurity()를 사용 | ||
.build(); | ||
``` | ||
|
||
채널 닫기 | ||
```java | ||
channel.shutdown(); | ||
``` | ||
|
||
## 스텁 stub | ||
|
||
**"메소드 스텁(method stub) 혹은 간단히 스텁은 소프트웨어 개발에 쓰이고 다른 프로그래밍 기능을 대리하는 코드이다" | ||
서버에 있는 함수가 Client에는 없으니까 `서버의 함수를 호출하듯이 서버 함수를 대신해주는 대신맨` ** | ||
|
||
|
||
### 동기 스텁 (blocking stub) | ||
동기 방식의 호출을 수행하며, 서버의 응답을 받을 때까지 클라이언트는 호출이 완료될 때까지 대기합니다. | ||
`예: HelloServiceGrpc.HelloServiceBlockingStub` | ||
|
||
### 비동기 스텁 (future stub) | ||
비동기 방식으로 Future 객체를 반환합니다. 응답을 즉시 기다릴 필요 없이 비동기 작업으로 처리할 수 있습니다. | ||
`예: HelloServiceGrpc.HelloServiceFutureStub` | ||
|
||
### 콜백 스텁 (async stub) | ||
비동기 방식으로 Future 객체를 반환합니다. 응답을 즉시 기다릴 필요 없이 비동기 작업으로 처리할 수 있습니다. | ||
`예: HelloServiceGrpc.HelloServiceFutureStub` | ||
|
||
### 스텁의 생성 및 사용 | ||
|
||
```java | ||
HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel); | ||
|
||
HelloRequest request = HelloRequest.newBuilder() | ||
.setName("ChatGPT") | ||
.build(); | ||
|
||
HelloResponse response = stub.sayHello(request); | ||
System.out.println("서버 응답: " + response.getMessage()); | ||
``` | ||
|
||
|
||
--- | ||
|
||
## grpc client 에서 jwt 포함하여 호출하기 | ||
|
||
|
||
```java | ||
public class JwtCallCredentials extends CallCredentials { | ||
private final String jwt; | ||
|
||
public JwtCallCredentials(String jwt) { | ||
this.jwt = jwt; | ||
} | ||
|
||
@Override | ||
public void applyRequestMetadata(RequestInfo requestInfo, | ||
Executor appExecutor, | ||
MetadataApplier applier) { | ||
appExecutor.execute(() -> { | ||
try { | ||
Metadata headers = new Metadata(); | ||
headers.put( | ||
Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER), | ||
"Bearer " + jwt); | ||
applier.apply(headers); | ||
} catch (Throwable e) { | ||
applier.fail(Status.UNAUTHENTICATED.withCause(e)); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
``` | ||
```java | ||
public HelloWorldClient(Channel channel, CallCredentials callCredentials) { | ||
blockingStub = GreeterGrpc.newBlockingStub(channel).withCallCredentials(callCredentials); | ||
} | ||
``` | ||
```java | ||
HelloWorldClient client = new HelloWorldClient(channel, new JwtCallCredentials("asdadsad")); | ||
client.greet(user); | ||
``` | ||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# spring security 6.x 버전에서 oauth2 사용해보기 | ||
|
||
## 1. OAuth2AuthorizationRequestRedirectFilter 를 통한 필터링 | ||
|
||
`http://localhost:8080/oauth2/authorization/google` 로 들어온 요청을 캐치해서 | ||
|
||
config 에 정의된 `redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"` 로 리다이렉트 시킨다, `response.sendRedirect(redirectUrl);` 이렇게 리스폰스 객체로 바로 리다이렉트 보내버림 | ||
|
||
|
||
## 2. OAuth2LoginAuthenticationFilter 를 통한 인증 처리 | ||
|
||
`Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)` 함수에서 인증 처리가 진행됨 | ||
|
||
- 사용자 요청을 `OAuth2AuthorizationRequest authorizationRequest` 로 만듬 | ||
- `authorizationRequest` 를 이용해 `OAuth2LoginAuthenticationToken authenticationRequest` 를 만듬 | ||
``` | ||
OAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken) this | ||
.getAuthenticationManager() | ||
.authenticate(authenticationRequest); | ||
``` | ||
- 위와 같이 `getAuthenticationManager` 를 이용하여 인증을 진행하여 `OAuth2LoginAuthenticationToken authenticationResult` 를 만들어냄 | ||
|
||
|
||
인증 완료되면 기본값으로 `"/"` path 로 리다이렉트 함, 그런데 서버가 `localhost:8080` 으로 동작 중이고, 웹 페이지가 `localhost:3000` 에서 동작중이면, | ||
`localhost:8080/` 로 리다이렉트되기 때문에 `/` 요청이 왔을 경우 로그인 요청이 왔던 `Referer` 주소로 리다이렉트 시켜줘야함 | ||
|
||
이는 별도의 복잡한 코딩없이 | ||
|
||
`successHandler.setUseReferer(true);` 만 해주면 요청했던 주소로 리다이렉트 됨 | ||
|
||
```java | ||
@Configuration | ||
@EnableWebSecurity | ||
public class SecurityConfig { | ||
|
||
private AuthenticationSuccessHandler getSuccessHandler() { | ||
var successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); | ||
successHandler.setUseReferer(true); | ||
return successHandler; | ||
} | ||
|
||
@Bean | ||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { | ||
|
||
http | ||
.authorizeHttpRequests(authorizeRequests -> authorizeRequests | ||
.anyRequest().authenticated()) | ||
.oauth2Login(httpSecurity -> httpSecurity.successHandler(getSuccessHandler())); | ||
|
||
return http.build(); | ||
} | ||
} | ||
``` | ||
|
||
코드를 직접 타고가면서 확인한 로직, | ||
|
||
`AbstractAuthenticationTargetUrlRequestHandler` 클래스의 아래 함수를 보면 알 수 있음 | ||
|
||
```java | ||
/** | ||
* Builds the target URL according to the logic defined in the main class Javadoc. | ||
*/ | ||
protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) { | ||
if (isAlwaysUseDefaultTargetUrl()) { | ||
return this.defaultTargetUrl; | ||
} | ||
String targetUrlParameterValue = getTargetUrlParameterValue(request); | ||
if (StringUtils.hasText(targetUrlParameterValue)) { | ||
trace("Using url %s from request parameter %s", targetUrlParameterValue, this.targetUrlParameter); | ||
return targetUrlParameterValue; | ||
} | ||
if (this.useReferer) { | ||
trace("Using url %s from Referer header", request.getHeader("Referer")); | ||
return request.getHeader("Referer"); | ||
} | ||
return this.defaultTargetUrl; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters