Spring Cloud – Angular 4の追加
1. 概要
前回のSpringCloudの記事では、アプリケーションにZipkinのサポートを追加しました。 この記事では、フロントエンドアプリケーションをスタックに追加します。
これまで、クラウドアプリケーションを構築するために完全にバックエンドに取り組んできました。 しかし、UIがない場合、Webアプリはどのようなメリットがありますか? この記事では、シングルページアプリケーションをプロジェクトに統合することで、この問題を解決します。
このアプリはAngularとBootstrapを使用して作成します。 Angular 4コードのスタイルは、Spring開発者にとって自然なクロスオーバーであるSpringアプリのコーディングによく似ています! フロントエンドコードはAngularを使用しますが、この記事の内容は最小限の労力で任意のフロントエンドフレームワークに簡単に拡張できます。
この記事では、Angular 4アプリを構築し、それをクラウドサービスに接続します。 SPAとSpring Securityの間でログインを統合する方法を示します。 また、AngularのHTTP通信のサポートを使用してアプリケーションのデータにアクセスする方法も示します。
2. ゲートウェイの変更
フロントエンドを配置したら、フォームベースのログインに切り替えて、UIの一部を特権ユーザーに保護します。 これには、ゲートウェイのセキュリティ構成を変更する必要があります。
2.1. HttpSecurityを更新
まず、ゲートウェイSecurityConfig.javaクラスのconfigure(HttpSecurity http)メソッドを更新しましょう。
@Override
protected void configure(HttpSecurity http) {
http
.formLogin()
.defaultSuccessUrl("/home/index.html", true)
.and()
.authorizeRequests()
.antMatchers("/book-service/**", "/rating-service/**", "/login*", "/")
.permitAll()
.antMatchers("/eureka/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.logout()
.and()
.csrf().disable();
}
まず、/home/index.htmlを指すデフォルトの成功URLを追加します。これは、Angularアプリが存在する場所になるためです。 次に、Eurekaリソースを除いて、ゲートウェイを介したすべての要求を許可するようにantマッチャーを構成します。 これにより、すべてのセキュリティチェックがバックエンドサービスに委任されます。
次に、デフォルトのログインページへのリダイレクトが正常に機能するため、ログアウト成功URLを削除しました。
2.2. プリンシパルエンドポイントを追加する
次に、認証されたユーザーを返すエンドポイントを追加しましょう。 これはAngularアプリで使用され、ログインしてユーザーのロールを特定します。 これは、サイトで実行できるアクションを制御するのに役立ちます。
ゲートウェイプロジェクトで、AuthenticationControllerクラスを追加します。
@RestController
public class AuthenticationController {
@GetMapping("/me")
public Principal getMyUser(Principal principal) {
return principal;
}
}
コントローラは、現在ログインしているユーザーオブジェクトを呼び出し元に返します。 これにより、Angularアプリを制御するために必要なすべての情報が得られます。
2.3. ランディングページを追加する
非常に単純なランディングページを追加して、ユーザーがアプリケーションのルートにアクセスしたときに何かが表示されるようにします。
src/main/resources/static,に、ログインページへのリンクを含むindex.htmlファイルを追加しましょう。
Book Rater Landing
Book Rater
So many great things about the books
Login
3. AngularCLIとスタータープロジェクト
新しいAngularプロジェクトを開始する前に、必ず最新バージョンのNode.js and npmをインストールしてください。
3.1. AngularCLIをインストールします
まず、npmを使用してAngularコマンドラインインターフェイスをダウンロードしてインストールする必要があります。 端末を開いて実行します。
npm install -g @angular/cli
これにより、CLIがグローバルにダウンロードおよびインストールされます。
3.2. 新しいプロジェクトをインストールする
ターミナルにいる間に、ゲートウェイプロジェクトに移動し、gateway / src / mainフォルダーに移動します。 「angular」というディレクトリを作成して、そこに移動します。 ここから実行:
ng new ui
我慢して; CLIが新しいプロジェクトを設定し、npmを使用してすべてのJavaScript依存関係をダウンロードします。 このプロセスに何分もかかることは珍しくありません。
ngコマンドはAngular CLIのショートカットであり、newパラメーターはCLIに新しいプロジェクトを作成するように指示し、uiコマンドはプロジェクトに名前を付けます。
3.3. プロジェクトを実行する
newコマンドが完了したら。 作成されたuiフォルダーに移動して実行します。
ng serve
プロジェクトがビルドされたら、http://localhost:4200に移動します。 ブラウザにこれが表示されるはずです。
おめでとうございます。 Angularアプリを作成しました!
3.4. ブートストラップをインストールする
npmを使用してブートストラップをインストールしましょう。 uiディレクトリから次のコマンドを実行します。
npm install [email protected] --save
これにより、ブートストラップがnode_modulesフォルダーにダウンロードされます。
uiディレクトリで、.angular-cli.jsonファイルを開きます。 これは、プロジェクトに関するいくつかのプロパティを設定するファイルです。 apps > stylesプロパティを見つけて、BootstrapCSSクラスのファイルの場所を追加します。
"styles": [
"styles.css",
"../node_modules/bootstrap/dist/css/bootstrap.min.css"
],
これにより、プロジェクトでビルドされたコンパイル済みCSSファイルにBootstrapを含めるようにAngularに指示されます。
3.5. ビルド出力ディレクトリを設定する
次に、Angularにビルドファイルを配置する場所を指定して、スプリングブートアプリがそれらを提供できるようにする必要があります。 Spring Bootは、resourcesフォルダーの2つの場所からファイルを提供できます。
-
src/main/resources/static
-
src/main/resource/public
すでに静的フォルダーを使用してEurekaのリソースを提供しており、Angularはビルドが実行されるたびにこのフォルダーを削除するため、Angularアプリをパブリックフォルダーにビルドしましょう。
.angular-cli.jsonファイルを再度開き、apps > outDirプロパティを見つけます。 そのstring:を更新します
"outDir": "../../resources/static/home",
Angularプロジェクトがsrc / main / angular / uiにある場合、それはsrc / main / resources / publicフォルダーにビルドされます。 アプリが別のフォルダーにある場合、場所を正しく設定するには、この文字列を変更する必要があります。
3.6. Mavenでビルドを自動化する
最後に、コードをコンパイルするときに実行される自動ビルドをセットアップします。 このantタスクは、「mvn compile」が実行されるたびに、Angular CLIビルドタスクを実行します。 このステップをゲートウェイのPOM.xmlに追加して、コンパイルするたびに最新のUI変更を取得できるようにします。
maven-antrun-plugin
generate-resources
run
この設定では、Angular CLIがクラスパスで利用可能である必要があることに注意してください。 このスクリプトをその依存関係のない環境にプッシュすると、ビルドが失敗します。
それでは、Angularアプリケーションの構築を始めましょう!
4. 角張った
チュートリアルのこのセクションでは、ページに認証メカニズムを構築します。 基本認証を使用し、簡単なフローに従って動作させます。
ユーザーには、ユーザー名とパスワードを入力できるログインフォームがあります。
次に、それらの資格情報を使用してbase64認証トークンを作成し、“/me”エンドポイントを要求します。 エンドポイントは、このユーザーのロールを含むPrincipalオブジェクトを返します。
最後に、後続のリクエストで使用するために、クライアントに資格情報とプリンシパルを保存します。
これがどのように行われるか見てみましょう!
4.1. テンプレート
ゲートウェイプロジェクトで、src/main/angular/ui/src/appに移動し、app.component.htmlファイルを開きます。 これはAngularがロードする最初のテンプレートであり、ユーザーがログインした後に着陸する場所になります。
ここでは、ログインフォームを含むナビゲーションバーを表示するためのコードを追加します。
Book Rater App
Anyone can view the books.
Users can view and create ratings
Admins can do anything!
このコードは、Bootstrapクラスでナビゲーションバーを設定します。 バーに埋め込まれているのは、インラインログインフォームです。 Angularはこのマークアップを使用してJavaScriptと動的にやり取りし、ページのさまざまな部分をレンダリングし、フォーム送信などを制御します。
(ngSubmit)=”onLogin(f)”のようなステートメントは、フォームが送信されたときにメソッド“onLogin(f)”を呼び出し、フォームをその関数に渡すことを示しています。 jumbotron div内には、主要オブジェクトの状態に応じて動的に表示される段落タグがあります。
次に、このテンプレートをサポートするTypescriptファイルをコーディングしましょう。
4.2. タイプスクリプト
同じディレクトリからapp.component.tsファイルを開きます。 このファイルには、テンプレート関数を作成するために必要なすべてのtypescriptプロパティとメソッドを追加します。
import {Component} from "@angular/core";
import {Principal} from "./principal";
import {Response} from "@angular/http";
import {Book} from "./book";
import {HttpService} from "./http.service";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
selectedBook: Book = null;
principal: Principal = new Principal(false, []);
loginFailed: boolean = false;
constructor(private httpService: HttpService){}
ngOnInit(): void {
this.httpService.me()
.subscribe((response: Response) => {
let principalJson = response.json();
this.principal = new Principal(principalJson.authenticated,
principalJson.authorities);
}, (error) => {
console.log(error);
});
}
onLogout() {
this.httpService.logout()
.subscribe((response: Response) => {
if (response.status === 200) {
this.loginFailed = false;
this.principal = new Principal(false, []);
window.location.replace(response.url);
}
}, (error) => {
console.log(error);
});
}
}
このクラスは、AngularライフサイクルメソッドngOnInit()にフックします。 このメソッドでは、/meエンドポイントを呼び出して、ユーザーの現在の役割と状態を取得します。 これにより、ユーザーにメインページに表示される内容が決まります。 このメソッドは、このコンポーネントが作成されるたびに起動されます。これは、アプリの権限についてユーザーのプロパティを確認する絶好の機会です。
また、ユーザーをログアウトしてこのページの状態を元の設定に復元するonLogout()メソッドもあります。
ただし、ここではいくつかの魔法が起こっています。 コンストラクターで宣言されているhttpServiceプロパティ。 Angularは、実行時にこのプロパティをクラスに注入します。 Angularは、Springのように、サービスクラスのシングルトンインスタンスを管理し、コンストラクターインジェクションを使用してインジェクトします。
次に、HttpServiceクラスを定義する必要があります。
4.3. HttpService
同じディレクトリに“http.service.ts”という名前のファイルを作成します。 このファイルに次のコードを追加して、ログインおよびログアウトメソッドをサポートします。
import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
import {Response, Http, Headers, RequestOptions} from "@angular/http";
import {Book} from "./book";
import {Rating} from "./rating";
@Injectable()
export class HttpService {
constructor(private http: Http) { }
me(): Observable {
return this.http.get("/me", this.makeOptions())
}
logout(): Observable {
return this.http.post("/logout", '', this.makeOptions())
}
private makeOptions(): RequestOptions {
let headers = new Headers({'Content-Type': 'application/json'});
return new RequestOptions({headers: headers});
}
}
このクラスでは、AngularのDIコンストラクトを使用して別の依存関係を注入しています。 今回はHttpクラスです。 このクラスはすべてのHTTP通信を処理し、フレームワークによって提供されます。
これらのメソッドはそれぞれ、AngularのHTTPライブラリを使用してHTTPリクエストを実行します。 各リクエストは、ヘッダーのコンテンツタイプも指定します。
次に、依存性注入システムにHttpServiceを登録するために、もう1つ実行する必要があります。 app.module.tsファイルを開き、providersプロパティを見つけます。 その配列にHttpServiceを追加します。 結果は次のようになります。
providers: [HttpService],
4.4. プリンシパルを追加
次に、TypescriptコードにプリンシパルDTOオブジェクトを追加しましょう。 同じディレクトリに「principal.ts」というファイルを追加し、次のコードを追加します。
export class Principal {
public authenticated: boolean;
public authorities: Authority[] = [];
public credentials: any;
constructor(authenticated: boolean, authorities: any[], credentials: any) {
this.authenticated = authenticated;
authorities.map(
auth => this.authorities.push(new Authority(auth.authority)))
this.credentials = credentials;
}
isAdmin() {
return this.authorities.some(
(auth: Authority) => auth.authority.indexOf('ADMIN') > -1)
}
}
export class Authority {
public authority: String;
constructor(authority: String) {
this.authority = authority;
}
}
PrincipalクラスとAuthorityクラスを追加しました。 これらは2つのDTOクラスで、SpringアプリのPOJOによく似ています。 そのため、これらのクラスをDIシステムに角度で登録する必要はありません。
次に、不明なリクエストをアプリケーションのルートにリダイレクトするようにリダイレクトルールを設定しましょう。
4.5. 404処理
ゲートウェイサービスのJavaコードに戻りましょう。 GatewayApplicationクラスが存在する場所に、ErrorPageConfigという新しいクラスを追加します。
@Component
public class ErrorPageConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/home/index.html"));
}
}
このクラスは404応答を識別し、ユーザーを“/home/index.html”にリダイレクトします。 シングルページアプリでは、クライアントがすべてのナビゲート可能なルートを処理する必要があるため、これは専用リソースに送信されないすべてのトラフィックを処理する方法です。
これで、このアプリを起動して、作成したものを確認する準備が整いました。
4.6. ビルドして表示
次に、ゲートウェイフォルダから「mvn compile」を実行します。 これにより、Javaソースがコンパイルされ、Angularアプリがパブリックフォルダーにビルドされます。 他のクラウドアプリケーション(config、discovery、およびzipkin)を起動してみましょう。 次に、ゲートウェイプロジェクトを実行します。 サービスが開始したら、http://localhost:8080に移動してアプリを表示します。 次のようなものが表示されるはずです。
次に、ログインページへのリンクをたどりましょう。
ユーザー/パスワード資格情報を使用してログインします。 「ログイン」をクリックすると、シングルページアプリがロードされる/home/index.htmlにリダイレクトされます。
jumbotronは、ユーザーとしてログインしていることを示しているようです。 次に、右上隅のリンクをクリックしてログアウトし、今回はadmin/admin資格情報を使用してログインします。
いいね! これで、管理者としてログインしました。
5. 結論
この記事では、シングルページアプリをクラウドシステムに統合するのがいかに簡単かを見てきました。 最新のフレームワークを使用して、実用的なセキュリティ構成をアプリケーションに統合しました。
これらの例を使用して、book-serviceまたはrating-serviceを呼び出すコードを記述してみてください。 HTTP呼び出しを行い、データをテンプレートにワイヤリングする例があるので、これは比較的簡単です。
サイトの残りの部分がいつものようにどのように構築されているかを知りたい場合は、ソースコードover on Githubを見つけることができます。