もなかアイスの試食品

「とりあえずやってみたい」そんな気持ちが先走りすぎて挫折が多い私のメモ書きみたいなものです.

SptingBoot(SpringSecurity)で簡単にログインパラメータを増やす方法

はじめに

SpringBootを使って新しいサービスを作ることになった

そのサービスでは、ログイン画面にログインIDとパスワード以外に、もう一つパラメータが必要

SpringBoot(SpringSecurity)ではログインIDとパスワードを使ったログイン認証が簡単に実装できるようになっているけど、他のパラメータを増やす方法を調べてみた。

パラメータ追加についての参考サイト

terasolunaorg.github.io

先にまず結論

参考にしたサイトではUsernamePasswordAuthenticationTokenやらUsernamePasswordAuthenticationFilterなどのクラスを継承するやり方が書いてあるけど・・・

結構面倒臭い(詳しくは参考サイトを見てほしい)

実装が終わった後、「パラメータ(パスワード以外)を区切り文字で全部くっつけた文字列」をログインIDとするほうが簡単で、認証処理がそのまま使えることに気がついた・・・

具体例

例えばログイン画面に以下のパラメータが必要だったとする

  • 会社コード
  • 従業員コード
  • パスワード

このとき、ユーザのDBテーブルは最低限の実装は以下の感じになると思う(会社コードと従業員コードが主キー)

会社コード 従業員コード ユーザ名 パスワード
100 1 しげる (ハッシュ値)
100 2 もりお (ハッシュ値)
100 3 やさお (ハッシュ値)
200 1 やばお (ハッシュ値)
200 2 まさよ (ハッシュ値)

このテーブルに「認証用に余計なカラム」を追加する

会社コード 従業員コード ログインID ユーザ名 パスワード
100 1 100__d(OvO)__1 しげる (ハッシュ値)
100 2 100__d(OvO)__2 もりお (ハッシュ値)
100 3 100__d(OvO)__3 やさお (ハッシュ値)
200 1 200__d(OvO)__1 やばお (ハッシュ値)
200 2 200__d(OvO)__2 まさよ (ハッシュ値)

ログインIDというカラムを追加し、会社コードと従業員コードを「__d(OvO)__」という文字列でくっつけたデータを入れている

ログインIDのカラムに「会社コード + __d(OvO)__ + 従業員コード」以外の文字列が入らないようにCHECK制約入れておくと安心

なぜ顔文字?というと

  1. 区切り文字が「@」だとメールアドレスを使用することになったら困るかも。他の記号も意外と危ないかな・・・?
  2. 記号を複数回・複数種類で組み合わせれば大丈夫じゃね?
  3. じゃぁ顔文字使えるじゃん!

という訳で特に理由はない

この追加したカラムをSpringBootで言うところのusernameに割り当てる

usernameパラメータはhtmlでhiddenにしておき、JavascriptなりjQueryなりでsubmitするときに、usernameパラメータを設定してあげる。

<form id="login-form" action="/login" method="post">
  <input type="hidden" id="user-name" name="username"/>
  <div>
    <label for="company-code">会社コード</label>
    <input id="company-code"/>
  </div>
  <div>
    <label for="employee-code">従業員コード</label>
    <input id="employee-code"/>
  </div>
  <div>
    <label for="password">パスワード</label>
    <input type="password" id="password" name="password"/>
  </div>
  <div>
    <input type="submit" value="ログイン"/>
  </div>
</form>
$('#login-form').submit(function() {
  var companyCode = $('#company-code').val();
  var employeeCode = $('#employee-code').val();
  $('#user-name').val(companyCode + '__d(OvO)__' + employeeCode);
  return true;
});

後の具体的な実装については、いろんなサイトに載っているSpringSecurityのログイン機能の実装の仕方と同じになる

実装例↓

qiita.com

認証処理のカスタムクラスを作ったときの面倒臭いところ

そもそもカスタムクラスを作るのが面倒臭い

ネットで調べたり、ソースコードを覗いたりすると、SpringSecurityのRememberMeの機能にも手を入れる必要があると気がついた。(RememberMe機能を利用する場合)

qiita.com

上記の記事を参考にすると、CookieにログインIDを保存している。

SpringSecurityのソースコードでも、Cookieからユーザを検索する処理が確認できた

public class TokenBasedRememberMeServices extends AbstractRememberMeServices {

    @Override
    protected UserDetails processAutoLoginCookie(String[] cookieTokens,
            HttpServletRequest request, HttpServletResponse response) {

        // 中略

        // Cookieからユーザを検索してるっぽい。引数は一個だけ
        UserDetails userDetails = getUserDetailsService().loadUserByUsername(
                cookieTokens[0]);

        // 中略

        return userDetails;
    }
}

ユーザの主キーは会社コードと従業員コードで設計したので、cookieTokens[0]に会社コードと従業員コードを入れてユーザを特定できるようにしないといけない

RememberMe用のCookie生成処理も手を入れないといけない

カスタムクラスの作成に意外と時間が掛かり、RememberMeも同じぐらい色々やらないといけなさそうと思ったとき、もう諦めの境地

おわりに

そもそも主キーの会社コードと従業員コードを文字列結合すれば、ユニークになるということに早く気がつけば・・・

調べ方が悪いのか、パラメータデータをくっつけてログインIDにするという方法は見つからない

邪道なんだろうか・・・