親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。

Spring Securityを使ったログイン機能 (1)未ログイン時の画面遷移


Spring BootのSpring security

Spring BootにはSpring securityという認証と認可を司るコンポーネントがありますが、これを使いながら数回に分けてログイン機能を実装したいと思います。
未ログイン時にログインフォームに遷移する動きから、最終的にはデータベースのユーザデータと認証をするところまで実装したいと思います。

ログイン画面の実装

まずはApplication起動用のパッケージを用意します。
Spring Bootでは何をするにもSpringApplication.runで起動しなければ始まりませんからね。
僕はsrc/main/java/パッケージ直下にApplication.javaというファイル名で配置しました。

package test.package;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

次にログインフォームを設置するので(今回は単純にHello Worldを表示するだけですが...)、
template/login直下にloginForm.htmlというテンプレートを用意します。

コントローラーはsrc/main/java/app/loginというパッケージを用意して、
LoginController.javaを作りました。

package test.package;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
@RequestMapping("login")
public class LoginController {
 
    @RequestMapping(value="")
    String loginForm() {
        return "login/loginForm";
    }
}

まずはこの時点でコンパイルし、localhost:8080/loginでログイン画面が表示されるか確認しましょう。
(何度も書きますが、今回は単純にHello Worldを表示するだけですが...w)、

f:id:tomotomo1129:20180609200926j:plain



ログインしていない時は閲覧不可に

さて、今普通に見れていたこのページをログインしていない状態では閲覧できないようにします。
ログインしていないのであればログインフォームは見れるようにしなければいけないですがwあくまで実験用です。
後から例外的にログインページだけ見れるようにします。

Spring Securityを使うには、spring-boot-starter-securityが必要なため、
pom.xmlに以下を追加してインポートします。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

続いて、WebSecurityConfigurerAdapterクラスを継承したクラスを作り、
各種必要な設定をしましょう。

まずはクラスの作成です。

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
 
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
}

こちらは設定クラスの作成なので@Configurationを付与します。
(後に@Beanアノテーションを付与したメソッドも定義するので、その意味でも@Configurationは必要です。)
「@EnableWebSecurity」はThymeleafを共に使うことで、formの中にCSRFのトークンが自動で埋め込まれます。
まだformは作りませんが、後で忘れないようにここで入れておきましょう。

※@Configurationとともに@EnableWebMvcSecurityのアノテーションを貼るソースコードをいくつか見かけましたが、
僕が使った最新のSpring Bootのバージョン(1.3.1.RELEASE)では非推奨になったようです。

次に例外となるディレクトリやファイルを設定します。
下記のようなディレクトリやファイルについては、ログインをしていようがしていまいがアクセスできるようにします。

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/favicon.ico", "/css/**", "/js/**", "/images/**", "/fonts/**");
}

次は認証が必要となるURLページの設定です。
以下の設定は、
「http.authorizeRequests()」は認証が必要となるURLを設定する関数で、
「antMatchers("〜").permitAll()」は認証が不要の例外ページ、
「anyRequest().authenticated();」で、それ以外のページは認証された状態でいる必要がある、ということになります。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests() // 認証が必要となるURLを設定します
        .antMatchers("/account/**").permitAll() // /account以下のURLも認証不要
        .anyRequest().authenticated(); // それ以外はすべて認証された状態じゃなきゃダメだよ〜
}

一旦この時点でプログラムを動かしてみましょう。
ログイン認証なしでアクセスが許されているのは、静的ファイルと/account/以下のURLのみです。
よって、当初は通っていたloginが通らなくなっているはずです。

コンパイルしてlocalhost/loginにアクセスすると...

f:id:tomotomo1129:20180609201324j:plain

ということでアクセスできなくなりました。
想定通りですね。



ログインフォームはログインしていなくても閲覧可能に

通常ログインフォームの画面に行く際は当然ログイン状態である必要はないので、認証不要のページにログインフォームも追加します。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests() // 認証が必要となるURLを設定します
        // ↓追加
        .antMatchers("/login").permitAll() // /loginFormは認証不要
        // ↑追加
        .antMatchers("/account/**").permitAll() // /account以下のURLも認証不要
        .anyRequest().authenticated(); // それ以外はすべて認証された状態じゃなきゃダメだよ〜
}

これでアクセスすれば再度問題なくログインフォームの画面は開きます。

ログインしていない場合はログインフォームに飛ばす

さて、最後にログインしていない場合にログインが必要なページに遷移した場合の挙動です。
以下のようにformLogin()で繋げて以下のようにURLを入力すれば、ログインしていない場合の挙動を設定することが可能になります。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/login").permitAll()
        .antMatchers("/account/**").permitAll()
        .anyRequest().authenticated()
    .and()
        .formLogin() // ログインページに飛ばすよ
        .loginProcessingUrl("/login") // ログイン処理をするURL
        .loginPage("/login"); // ログインページのURL

これで未ログイン時の挙動はできましたね。
以下のページでは、ログインフォームを本格的に作成する手順について掲載しています。

ti-tomo-knowledge.hatenablog.com

こちらも参考にしてみてください。


Spring Boot 2 プログラミング入門

Spring Boot 2 プログラミング入門

Spring Boot プログラミング入門

Spring Boot プログラミング入門

Spring Boot in Action

Spring Boot in Action