AngularのSpring Securityログインページ
1. 概要
このチュートリアルでは、login page using Spring Security with:を作成します
-
AngularJS
-
角度2、4、5、および6
ここで説明するサンプルアプリケーションは、基本HTTP認証で保護されたRESTサービスと通信するクライアントアプリケーションで構成されています。
2. Spring Securityの構成
まず、SpringSecurityとBasicAuthを使用してRESTAPIを設定しましょう。
構成方法は次のとおりです。
@Configuration
@EnableWebSecurity
public class BasicAuthConfiguration
extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}
@Override
protected void configure(HttpSecurity http)
throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
}
それでは、エンドポイントを作成しましょう。 RESTサービスには、ログイン用とユーザーデータの取得用の2つがあります。
@RestController
@CrossOrigin
public class UserController {
@RequestMapping("/login")
public boolean login(@RequestBody User user) {
return
user.getUserName().equals("user") && user.getPassword().equals("password");
}
@RequestMapping("/user")
public Principal user(HttpServletRequest request) {
String authToken = request.getHeader("Authorization")
.substring("Basic".length()).trim();
return () -> new String(Base64.getDecoder()
.decode(authToken)).split(":")[0];
}
}
同様に、承認用のOAuth2サーバーの実装に関心がある場合は、Spring Security OAuth2に関する他のチュートリアルも確認できます。
3. Angularクライアントのセットアップ
RESTサービスを作成したので、さまざまなバージョンのAngularクライアントでログインページを設定しましょう。
ここで説明する例では、依存関係の管理にnpmを使用し、アプリケーションの実行にnodejsを使用しています。
Angularは、すべての子コンポーネント(この場合はログインコンポーネントとホームコンポーネント)が共通の親DOMに挿入される単一ページアーキテクチャを使用します。
JavaScriptを使用するAngularJSとは異なり、Angularバージョン2以降はTypeScriptを主言語として使用します。 したがって、アプリケーションには、正しく動作するために必要な特定のサポートファイルも必要です。
Angularのインクリメンタル拡張により、必要なファイルはバージョンごとに異なります。
これらのそれぞれについて理解しましょう。
-
systemjs.config.js –システム構成(バージョン2)
-
package.json –ノードモジュールの依存関係(バージョン2以降)
-
tsconfig.json –ルートレベルのTypescript構成(バージョン2以降)
-
tsconfig.app.json –アプリケーションレベルのTypescript構成(バージョン4以降)
-
.angular-cli_.json_ – Angular CLI構成(バージョン4および5)
-
angular.json – Angular CLI構成(バージョン6以降)
4. ログインページ
4.1. AngularJSを使う
index.htmlファイルを作成し、それに関連する依存関係を追加しましょう。
これはシングルページアプリケーションであるため、すべての子コンポーネントは、ルーティングロジックに基づいてng-view属性を使用してdiv要素に追加されます。
次に、URLからコンポーネントへのマッピングを定義するapp.jsを作成しましょう。
(function () {
'use strict';
angular
.module('app', ['ngRoute'])
.config(config)
.run(run);
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider) {
$routeProvider.when('/', {
controller: 'HomeController',
templateUrl: 'home/home.view.html',
controllerAs: 'vm'
}).when('/login', {
controller: 'LoginController',
templateUrl: 'login/login.view.html',
controllerAs: 'vm'
}).otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$http', '$window'];
function run($rootScope, $location, $http, $window) {
var userData = $window.sessionStorage.getItem('userData');
if (userData) {
$http.defaults.headers.common['Authorization']
= 'Basic ' + JSON.parse(userData).authData;
}
$rootScope
.$on('$locationChangeStart', function (event, next, current) {
var restrictedPage
= $.inArray($location.path(), ['/login']) === -1;
var loggedIn
= $window.sessionStorage.getItem('userData');
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
})();
ログインコンポーネントは、login.controller.jsとlogin.view.html.の2つのファイルで構成されています。
最初のものを見てみましょう:
Login
そして2つ目:
(function () {
'use strict';
angular
.module('app')
.controller('LoginController', LoginController);
LoginController.$inject = ['$location', '$window', '$http'];
function LoginController($location, $window, $http) {
var vm = this;
vm.login = login;
(function initController() {
$window.localStorage.setItem('token', '');
})();
function login() {
$http({
url: 'http://localhost:8082/login',
method: "POST",
data: {
'userName': vm.username,
'password': vm.password
}
}).then(function (response) {
if (response.data) {
var token
= $window.btoa(vm.username + ':' + vm.password);
var userData = {
userName: vm.username,
authData: token
}
$window.sessionStorage.setItem(
'userData', JSON.stringify(userData)
);
$http.defaults.headers.common['Authorization']
= 'Basic ' + token;
$location.path('/');
} else {
alert("Authentication failed.")
}
});
};
}
})();
コントローラーは、ユーザー名とパスワードを渡すことでRESTサービスを呼び出します。 認証が成功すると、ユーザー名とパスワードがエンコードされ、エンコードされたトークンが将来の使用に備えてセッションストレージに保存されます。
ログインコンポーネントと同様に、ホームコンポーネントもhome.view.html:の2つのファイルで構成されています
Hi {{vm.user}}!
You're logged in!!
およびhome.controller.js:
(function () {
'use strict';
angular
.module('app')
.controller('HomeController', HomeController);
HomeController.$inject = ['$window', '$http', '$scope'];
function HomeController($window, $http, $scope) {
var vm = this;
vm.user = null;
initController();
function initController() {
$http({
url: 'http://localhost:8082/user',
method: "GET"
}).then(function (response) {
vm.user = response.data.name;
}, function (error) {
console.log(error);
});
};
$scope.logout = function () {
$window.sessionStorage.setItem('userData', '');
$http.defaults.headers.common['Authorization'] = 'Basic';
}
}
})();
ホームコントローラーは、Authorizationヘッダーを渡すことによってユーザーデータを要求します。 RESTサービスは、トークンが有効な場合にのみユーザーデータを返します。
次に、Angularアプリケーションを実行するためのhttp-serverをインストールしましょう。
npm install http-server --save
これがインストールされたら、コマンドプロンプトでプロジェクトルートフォルダーを開き、コマンドを実行できます。
http-server -o
4.2. Angularバージョン2、4、5の使用
バージョン2のindex.htmlは、AngularJSバージョンとは少し異なります。
Loading...
main.tsは、アプリケーションのメインエントリポイントです。 アプリケーションモジュールをブートストラップし、その結果、ブラウザーがログインページを読み込みます。
platformBrowserDynamic().bootstrapModule(AppModule);
app.routing.tsは、アプリケーションのルーティングを担当します。
const appRoutes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: '**', redirectTo: '' }
];
export const routing = RouterModule.forRoot(appRoutes);
app.module.tsはコンポーネントを宣言し、関連するモジュールをインポートします。
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
routing
],
declarations: [
AppComponent,
HomeComponent,
LoginComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }
シングルページアプリケーションを作成しているので、すべての子コンポーネントを追加するルートコンポーネントを作成しましょう。
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent { }
app.component.htmlには、<router-outlet>タグのみが含まれます。 Angularは、ロケーションルーティングメカニズムにこのタグを使用します。
次に、ログインコンポーネントとそれに対応するテンプレートをlogin.component.ts:で作成しましょう
@Component({
selector: 'login',
templateUrl: './app/login/login.component.html'
})
export class LoginComponent implements OnInit {
model: any = {};
constructor(
private route: ActivatedRoute,
private router: Router,
private http: Http
) { }
ngOnInit() {
sessionStorage.setItem('token', '');
}
login() {
let url = 'http://localhost:8082/login';
let result = this.http.post(url, {
userName: this.model.username,
password: this.model.password
}).map(res => res.json()).subscribe(isValid => {
if (isValid) {
sessionStorage.setItem(
'token',
btoa(this.model.username + ':' + this.model.password)
);
this.router.navigate(['']);
} else {
alert("Authentication failed.");
}
});
}
}
最後に、login.component.htmlを見てみましょう。
4.3. Angular6の使用
Angularチームはバージョン6でいくつかの機能強化を行いました。 これらの変更により、この例は他のバージョンと比較して少し異なります。 バージョン6に関してこの例で行った唯一の変更は、サービス呼び出し部分です。
HttpModuleの代わりに、バージョン6はHttpClientModuleをからインポートします @angular/common/http.
サービス呼び出し部分も古いバージョンと少し異なります。
this.http.post>(url, {
userName: this.model.username,
password: this.model.password
}).subscribe(isValid => {
if (isValid) {
sessionStorage.setItem(
'token',
btoa(this.model.username + ':' + this.model.password)
);
this.router.navigate(['']);
} else {
alert("Authentication failed.")
}
});
5. 結論
Angularを使用してSpringSecurityログインページを実装する方法を学びました。 バージョン4以降、Angular CLIプロジェクトを使用して、開発とテストを簡単に行うことができます。
いつものように、ここで説明したすべての例は、Github projectにあります。