1
0

More than 1 year has passed since last update.

【Angularアプリケーション開発 #9】ログイン機能とセッション管理について

Posted at

はじめに

今回、IDとパスワードでのログインを実装しました。
また、ログイン後の画面に直接アクセスした場合、ログイン状態を確認し、遷移先を分岐させるようにしました。

ログイン

ログイン画面

login.component.html
<div class="container">
    <h1>Login</h1>
    <form (ngSubmit)="onSubmit()" #loginForm="ngForm">
        <table>
            <tr>
                <td><label for="id">名前</label></td>
                <td><input type="text" id="id" required [(ngModel)]="model.loginId" name="idName" (blur)="idValid()">
                    <span *ngIf="idVaridFlg">
                        名前を入力して下さい。
                    </span>
                </td>
            </tr>
            <tr>
                <td><label for="password">パスワード</label></td>
                <td><input type="text" id="password" required [(ngModel)]="model.password" name="passName" (blur)="passwordValid()">
                    <span *ngIf="passwordVaridFlg">
                        パスワードを入力して下さい。
                    </span>
                </td>
            </tr>
        </table>
        <button type="submit" [disabled]="!loginForm.form.valid">ログイン</button>
        <br /> {{model.message}}
    </form>
    <button (click)="define()">セッションの削除</button>
</div>

ログイン処理

簡単に説明すると、IDとパスワードをPOSTでバックエンド側にリクエストしています。
ステータス200が返ってきた場合は、次のページへ遷移させています。

  onSubmit(): void {
    this.auth();
  }
  auth(): void {
    const myAsync = async (url) => {
      const headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      };
      const obj = this.model;
      const body = JSON.stringify(obj);
      const response = await fetch(url,{method: "POST",credentials: 'include', headers:headers,body:body}); //await で fetch() が完了するまで待つ
      return response.status;
    }
    myAsync(this.Host + '/sessionsave').then((data)=>{
      if(data == 200){
        this.router.navigate(['members']);
      }else{
        this.model.message = 'ログインに失敗しました';
      }
    }).catch((err) => console.log('セッション情報の生成に失敗'));
  }

ログイン処理でリクエストしているAPIです。
内容としては、ボディにセットされているIDとパスワードが正しい場合にセッション情報を作成しています。
また、今回はCookieも一応セットするようにしています。
補足ですが、Cookieとセッションは分けて考えたほうが良いです。
セッションもCookieを使用していますが、セッションIDをCookieに保存しています。
セッションで保存された情報はサーバ側にあります。また、セッションの情報はサーバ側で削除することもできます。
Cookieだけでもセッションを実現することはできますが、常にキーと値をフロントとバックを行き来することになるのと、その値は、デベロッパーツールで簡単に見ることができるので、セキュリティ的に弱いです。
例えば、ログアウトしてもCookieにキーと値をセットしてサーバ側に送信すればなりすましでログインできてしまいます。
DBを介せばCookieだけでもセッション管理できそうですが。。

    @PostMapping("/sessionsave")
    public void save(HttpServletResponse response, @RequestBody LoginInfo loginInfo) {

    	if(loginInfo.getLoginId().equals("×××") && loginInfo.getPassword().equals("×××")) {
        	Cookie cookie = new Cookie("key", "value");
        	response.addCookie(cookie);
        	session.setAttribute("key", cookie.getValue());
    	}
    }

直アクセスへの対応(ガード処理)

ガード処理

バック側へセッションが有効かどうかをリクエストしています。

auth.guard.ts
canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
      this.authCheck();
    return true;
  }
  authCheck(): void {
    const myAsync = async (url) => {
      const response = await fetch(url,{credentials: 'include'});
      const data = await response.json();
      if(data.cookieValidFlag){
        this.router.navigate(['members']);
        
      }else{
        this.router.navigate(['login']);
      }
      return data;
    }
    myAsync(this.Host + '/sessionload').then().catch((err) => console.log("データ取得に失敗"));
  }

判定を入れたいコンポーネントにcanActivate: [AuthGuard]を記載しています。

app-routing.module.ts
const routes: Routes = [
  {path:'', redirectTo: '/login',pathMatch: 'full'},
  {path:'login', component: LoginComponent},
  {path:'members', component: MembersComponent, canActivate: [AuthGuard]}
]

java側の処理です。
セッションがnullでないことを確認しています。
nullでなければ、フロントに有効であることを返しています。

    // セッションの取得
    @GetMapping("/sessionload")
    public CookieInfo load(
    		@CookieValue(name = "key", required = false) String value)  {
    	String result =  (String)session.getAttribute("key");  // 取得
    	CookieInfo cookieInfo = new CookieInfo();
    	cookieInfo.setCookieValidFlag(false);
    	if(result != null) {
    		cookieInfo.setCookieValidFlag(true);
    	}
    	return cookieInfo;
    }

おわりに

どうでしたでしょうか。
かなり端折っていますが、重要な部分は記載できていると思います。
今回は触れていませんが、セッションIDをリクエストに付加して送る場合は、java側でフロントのURLを設定しておく必要がありました。
IDとパスワードはjavaのsrcに直接書いていますが、通常はDBに登録していると思うので、そちらは各々で変更してください。
もうセッションを使った認証は古いかもしれませんが、、良ければ参考程度に見てください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0