アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うことを書いてます。

SpringSecurity:デフォルトのログイン画面をオリジナルログイン画面に変更する  SpringBoot/thymeleaf

 SpringBootのSpringSecurityの使い方について、前回からやってます。

arakan-pgm-ai.hatenablog.com

 

前回は、とりあえず使うことと、ロール(権限)によって、ページの項目を部分的に表示・非表示を制御するのをやりました・・が、実用的ではないです。 

せめて、ログインフォームをオリジナルページにして、DBで認証するくらいのことはしないと・・ですね。 

なので、それをやっていくのですが、一気にやると説明がわかりづらくなりやすい部分でもあります。 

ということで、DBで認証する部分は次回にして、今回は「ログインフォームをオリジナルページにする」という部分をやります。

 

オリジナルログインページのHTMLをつくる

 

 ログイン画面用のHTMLを用意します。 

凝るのも面倒なので、最低限のフォームにしておきます。 

イメージはこんな感じ。

f:id:arakan_no_boku:20180319001634j:plain

 

login.html のHTMLソースです。

<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sample App</title>
  <link th:href="@{/css/styles.css}" rel="stylesheet"/>
</head>
<body>
<div class="box">
   <h1>オリジナルログインフォームです</h1>
   <form role="form" id="login" th:action="@{/login}" method="post">
        <div th:if="${iserror}" style="color:red;">
            <p>ログインできませんでした。やりなおしてください。</p>
        </div>
        <p>ユーザID</p>
        <input type="text" id="username" name="username" autofocus="autofocus" />
        <p>パスワード</p>
        <input type="password" id="password" name="password" /><br/>
        <button type="submit">ログイン</button>
   </form>
</div>
</body>
</html>

 

ポイントだけ補足します。 

ログインエラーメッセージを表示する箇所は以下のようにしてます。

        <div th:if="${iserror}" style="color:red;">
            <p>ログインできませんでした。やりなおしてください。</p>
        </div>

 

コントローラクラスで、iserrorという変数のエラーでの表示(true)か否(false)かがセットされて渡ってくる前提で、エラーメッセージの表示・非表示を切り替えているだけです。 

別にこうしないといけないという訳ではないですが、とりあえず、シンプルで悩むところの少ない、ひとつのやり方ではあります。 

もうひとつ、ユーザー名を入力するテキストボックスのnameは「username」、パスワードを入力するテキストボックスのnameは「password」です。 

これを違う名前にすると、正しくユーザIDとパスワードを入力しているのに、認証エラーになる・・みたいなことで悩むことになります。 

変更する方法はあるみたいですが、あえて変更することに、手間に見合うメリットがない限りはあわせておくことをおすすめします。 

 参考までに、CSSは外部ファイルにして、以下の最低限の設定だけしています。

@CHARSET "UTF-8";

html {
    font-size:16px
}

body {
    font-family: 'メイリオ','Hiragino Kaku Gothic Pro',sans-serif;
    background-color:white;
}

.box{
    wide:100%;
    text-align:center;
}    

p{
	margin-left:1em;
	margin-right:auto;
	margin-top:0.5em;
	margin-bottom:0.5em;
}

input[type="text"]{
	
	margin-left:1em;
    margin-top:0.5em;
    margin-bottom:0.5em;
	height:2em;
	line-height:2em;
	paddhing:1em;
	
}

input[type="password"]{
    
    margin-left:1em;
    margin-top:0.5em;
    margin-bottom:0.5em;
    height:2em;
    line-height:2em;
    paddhing:1em;
    
}

 

JAVAコンフィグクラスにオリジナルフォームを使う設定をする

 

Spring Securityの設定はXMLで行う方法もありますが、自分はXMLを増やすのが嫌いなので、Javaで設定する方法をとります。 

configパッケージを作って、Spring Securityの設定を行うクラスをその下に作ります。 

決まった名前付けルールとかはありません。 

違うパッケージの下に違うクラス名で作っても構いません。 

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Override
	protected void configure(HttpSecurity web)throws Exception{
		
		web.formLogin().loginPage("/login").defaultSuccessUrl("/inpg01").failureUrl("/login-error").permitAll();
		web.authorizeRequests().antMatchers("/css/**", "/images/**", "/js/**").permitAll().anyRequest().authenticated();
	}
}

 

まず、絶対の前提条件です。

  • 必ず「WebSecurityConfigurerAdapter」を継承します。
  • 必ず「@EnableWebSecurity」アノテーションをつけます。
  • 必ず「configure」メソッドをオーバーライドします。

 

次に以下の部分の説明です。

web.formLogin().loginPage("/login").defaultSuccessUrl("/inpg01").failureUrl("/login-error").permitAll();

 

formLogin() は「フォーム認証を行う」。

loginPage("/login") は「ログインページを表示するURLは/login」

defaultSuccessUrl("/inpg01")は「認証成功時のデフォルト遷移先URLは/inpg01」

failureUrl("/login-error")は、「認証失敗時の遷移先URLは/login-error」

.permitAll(); は、「すべてのユーザに対して、ログインページへのアクセスを許す」

です。 

ようするに、オリジナルログインページを認証で使うための宣言です。 

認証失敗時のURLを指定しなくても、デフォルトで「login?error」みたいに、ログインページのURLに?errorのパラメータをつけて遷移してくれますが、明示的に指定しておいたほうがわかりやすいかな・・。 

続けて、以下の部分です。

web.authorizeRequests().antMatchers("/css/**", "/images/**", "/js/**").permitAll().anyRequest().authenticated();

 

anyRequest().authenticated() は、すべてのユーザは認証されているユーザ以外にアクセスは許さないという指定です。 

ただ、それだけだと、ログインページを表示する時にCSSファイルや画像ファイルにもアクセスできなくなってしまいます。 

なので、その前の「antMatchers("/css/**", "/images/**", "/js/**").permitAll()」でstaticフォルダのCSS,images、jsフォルダに対してはすべてのユーザのアクセスを許すようにしています。

 

コントローラクラスを作成する

 

ここまでできたら、あとはログインページのコントローラクラスを作るだけです。 

LoginController.javaという名前にします。 

ログイン成功時の遷移先「/inpg01」は前回作成したページをそのまま使います。

arakan-pgm-ai.hatenablog.com

 

だから、LoginControllerクラスで作成するの必要があるは、「/login」と「/login-error」の2つです。

@Controller
public class LoginController {
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String index(Model model) {
		model.addAttribute("iserror",false);
	    return "login";
	}
	
	@RequestMapping(value = "/login-error", method = RequestMethod.GET)
	public String loginError(Model model) {
		 model.addAttribute("iserror",true);
		 return "login";
	}
	
}

 

ごくシンプルに、どちらも「login.html」を呼び出してます。 

違いは、「iserror」にfalseをセットしているか、true(エラーメッセージを表示)にしているか・・くらいです。

 

さて実行してみます。

 

 認証時のユーザ名とパスワードと権限は、前回同様、プロパティファイルで指定するパターンのままでやってみます。

arakan-pgm-ai.hatenablog.com

 

今回はUSERロールでやってみます。

spring.security.user.name=user
spring.security.user.password=demo
spring.security.user.roles=USER

 

これで前回同様にまず「/inpg01」にアクセスすると、まだログインしていないのでログイン画面が表示されます。

f:id:arakan_no_boku:20180319224222j:plain

 

まずエラーページをみたいので、上記のように適当なユーザ名とパスワードを入力してログインボタンを押してみます。

f:id:arakan_no_boku:20180319224437j:plain

 

ちゃんとエラーページに遷移してますので、今度は正しく「user」「demo」を入力してログインします。

f:id:arakan_no_boku:20180319224637j:plain

 

OKですね。 

オリジナルのログイン画面に変更することができました。 

次回は、ログイン名とパスワードを複数管理できるようにDB認証に切り替えるようにします。 

今回はこんなところで。

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

  

f:id:arakan_no_boku:20170725215801j:plain