Posted at

Spring Cloudでマイクロサービス

More than 1 year has passed since last update.

Spring cloud を使用してシンプルなマイクロサービスを構成します。ログインにはOAuth2を使用してGoogleアカウントでログインできるようにします。ソースは https://github.com/jun-1/spring-cloud-microservices


全体構成

ブラウザ等のクライアントとの対話やログイン処理はweb-serviceが行いbackend-serviceに各種機能を要求します。この際discovery-serviceにサービスを登録することで各サービスがお互いを見つけられるようにします。

image


discovery-seriviceの実装

@EnableEurekaServerアノテーションを付けたspring-bootアプリケーションを作成するだけでサービスレジストリとしてEurekaサーバーが実装できます。

また http://localhost:8761 からステータスを確認できます。

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class DeiscoveryServiceApplication {

public static void main(String[] args) {
SpringApplication.run(DeiscoveryServiceApplication.class, args);
}
}

ポート番号と自分自身をレジストリに登録しないため設定をします。

eureka:

client:
register-with-eureka: false
fetch-registry: false
server:
port: 8761


web-serviceの実装

はじめにOAuthで使用するクライアントIDとクライアントシークレットを取得します。


Googleの認証情報作成

https://console.developers.google.com で認証情報を作成します。

image

[認証情報]から[プロジェクトを作成]をクリックしプロジェクトを作成します。

image

OAuthクライアントIDを選択し認証情報を作成します。(OAuth同意画面を作成していない場合は作成しておきます)

image

localhostで動かす場合は[その他]を選択して[作成]ボタンをクリックすると、OAuthクライアントのクライアントIDとクライアントシークレットが取得できます。


アプリケーションの実装

web-serviceの役割はクライアントとの対話とログイン、それからbackend-serviceに対するリバースプロキシです。

@EnableZuulProxyをつけることでZuulを使用してCORSと認証の懸念事項を個別に管理することなくリバースプロキシとして動作させることができます。

@EnableOAuth2SsoをつけることでOAuth2に基づくシングルサインオンが実現できます。

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableEurekaClient
@EnableZuulProxy
@EnableOAuth2Sso
@SpringBootApplication
public class WebServiceApplication extends WebSecurityConfigurerAdapter{

public static void main(String[] args) {
SpringApplication.run(WebServiceApplication.class, args);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "index.html").permitAll()
.anyRequest().authenticated();
}
}

configure()ではindex.html以外のURLへのアクセスには認証が必要と設定しています。

次はweb-serviceの設定です。

spring:

application:
name: web-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
zuul:
ignored-services: '*'
routes:
backend-service: 'api/**'
security:
oauth2:
resource:
user-info-uri: https://www.googleapis.com/oauth2/v1/userinfo
client:
access-token-uri: https://accounts.google.com/o/oauth2/token
user-authorization-uri: https://accounts.google.com/o/oauth2/auth
client-id: ${clientId}
client-secret: ${clientSecret}
grant-type: code
scope: profile

spring.application.nameで設定した名前でEurekaサーバーにサービスが登録されます。

登録先のサーバーはeureka.client.service.url.defaultZoneで指定します。

zuulの設定でapi/**へのリクエストをbackend-serviceに転送するようにしています。

ここでは転送先にEurekaサーバーに登録したサービス名を使用できます。

securityの設定はOAuth2クライアントの設定です。ここで先ほど取得したクライアントIDとクライアントシークレットを使用します。


backend-service

backend-serviceはOAuth2のクライアントでありリソースサーバーとして実装しています。

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@EnableEurekaClient
@EnableOAuth2Client
@EnableResourceServer
@SpringBootApplication
public class BackendServiceApplication {

public static void main(String[] args) {
SpringApplication.run(BackendServiceApplication.class, args);
}
}

以下は'Hello'の文字列を返すだけのコントローラーですが、OAuth2の認証がなければアクセスできないようになります。web-service経由でアクセスした場合はZuul Proxyが認証トークンをリレーしてくれるためweb-serviceでログインしていれば/api/helloで呼び出すことが可能です。

package demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BackendController {

@RequestMapping("/hello")
public String hello(){
return "Hello";
}
}

また、以下のようにOAuth2RestTemplateを使用すると、他のサービスとRest通信を簡単に行うことができます。

    @Bean

@LoadBalanced
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context){
return new OAuth2RestTemplate(resource, context);
}