49
48

More than 5 years have passed since last update.

AngularJS+JavaEEでセッション管理

Last updated at Posted at 2014-05-26

AngularJS + JavaEE7 でログイン・ログアウトと、認証の処理について実装してみたときのメモ。

動作確認は GlassFish 4.0 上で実施。

GitHub サンプル

認証処理を入れた場所

次の2カ所で、ログインしているかどうかのチェックを入れている。

  1. REST のリクエストがあったとき
  2. ページ遷移のとき

REST のリクエストがあったときのチェック

Filter でチェック

Filter を作成して、そこでチェックを行っている。

SessionFilter.java
package sample.angular.filter;

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sample.angular.rest.session.UserSession;

@WebFilter("/rest/*")
public class SessionFilter implements Filter {

    @Inject
    private UserSession userSession;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;

        if (this.needsSessionCheck(req) && !this.userSession.isLogged()) {
            res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        } else {
            chain.doFilter(request, response);
        }
    }

    private boolean needsSessionCheck(HttpServletRequest req) {
        return !req.getRequestURI().endsWith("/session");
    }

    @Override public void destroy() {/*no use*/}
    @Override public void init(FilterConfig filterConfig) throws ServletException {/*no use*/}
}

認証チェックが必要なリクエスト(/rest/session 以外へのリクエスト)の場合、 UserSession の状態をチェックして認証済みか確認している。
認証済み出ない場合は 401 のエラーをクライアントに返している。

UserSession で認証情報を保持する

UserSession は CDI の SessionScoped で管理しているインスタンスで、内部にログイン済みかどうかのフラグを持っている。

UserSession.java
package sample.angular.rest.session;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;

@SessionScoped
public class UserSession implements Serializable {
    private static final long serialVersionUID = 1L;

    @Inject
    private HttpSession session;

    private boolean isLogged;

    public void start() {
        this.isLogged = true;
    }

    public boolean isLogged() {
        return this.isLogged;
    }

    public void end() {
        this.isLogged = false;
        this.session.invalidate();
    }
}

ログイン時に start() メソッドを実行し、ログアウトするときに end() メソッドを実行してセッションを破棄する。

サーバーから 401 が返されたときは、クライアントでページを強制遷移させる

interceptors.js
angular
.module('mine')
.factory('SessionInterceptor', function($q, $location) {
    return {
        responseError: function(response) {
            // サーバーからのレスポンスが 401 ならトップページに強制遷移する
            if (response.status === 401) {
                $location.path('/');
            }

            return $q.reject(response);
        }
    };
});

$http の処理にインターセプターをかませて、サーバーからのレスポンスコードが 401 の場合に、強制的にログイン画面に遷移するようにしている。

ページ遷移のときのチェック

ページが切り換わるときのイベントをフックして、都度サーバーに認証情報の問い合わせを行うようにしている。

app.js
angular
.module('mine', ['ngRoute'])
.config(function($httpProvider) {
    $httpProvider.interceptors.push('SessionInterceptor');
})
.config(function($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'app/view/login.html',
            controller: 'LoginController',
            needsAuth: false
        })
        .when('/sample', {
            templateUrl: 'app/view/sample.html',
            controller: 'SampleController',
            needsAuth: true
        });
})
.run(function($rootScope, sessionService, $location) {
    // ページが切り換わるごとに、認証が必要なページの場合はサーバーにセッションの問い合わせを行う
    $rootScope.$on('$routeChangeSuccess', function(event, current, next) {
        if (current.needsAuth) {
            sessionService.inquire();
        }
    });
});

$routeScope.$on("$routeChangeSuccess", callback) でページ遷移のイベントをフックできる。

このタイミングで認証が必要なページかどうかを確認して、必要であればサーバーに確認のリクエストを送信する。

401 が返された場合は、先ほどのインターセプターによってログイン画面に強制遷移させられる。

認証が必要かどうかを判断するための値(needsAuth)は、 when() メソッドでルートを設定するときの引数で指定している。

49
48
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
49
48