SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

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

 SpringBootに用意された、高機能なセキュリティ機構「SpringSecurity」を使います。

STS3(3.9.6)+SpringBoot2.0+Tymeleaf3.0迄動作確認しています。

今回は「ログインフォームをオリジナルページにする」という部分をやります。

f:id:arakan_no_boku:20190222012501j:plain

 

オリジナルログインページの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ですね。 

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

今回はこんなところで。

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com