0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ログイン認証について

Posted at

はじめに

SpringSecurityを使用したログイン認証については、framework内で処理が行われているため、少々わかりにくいことがあるかと思います。認証プロセスを理解することで認証周りの開発も躓くことなく進められると思いますので、認証プロセスについて解説していきます。

SpringSecurityを使用した認証プロセス

ログイン認証時のユーザー名とパスワードの検証は、Spring Securityの認証プロセス内で行われています。具体的には、以下の流れになります。

  1. ユーザがログインフォームからユーザ名とパスワードを入力して送信します
  2. UsernamePasswordAuthenticationFilterがリクエストを受け取り、ユーザー名とパスワードを抽出します
  3. AuthenticationManagerによって認証プロセスが開始されます
  4. 取得したユーザー情報のパスワードと、入力されたパスワードをPasswordEncoderを使用して比較します
  5. パスワードが一致すれば認証成功となり、ユーザーの認証情報がSecurityContextHolderに保存されます
  6. パスワードが一致しない場合は認証失敗となり、エラーが返されます

認証後は、認証情報はSecurityContextHolderに保持されます。
SecurityContextHolderのAuthenticationをクリアすることでログアウト可能となります。

ログイン認証についてのサンプルコード

認証機能、ログイン画面、ホーム画面(認証後表示)、ログアウト機能を作成しました。
認証用のユーザについてはInMemoryUserDetailsManagerを使用してメモリ上に保持しています。サンプルコードを記載します。

認証、ログアウト機能

AuthenticationManagerUserDetailsServicePasswordEncoderの組み合わせで認証プロセスが開始されます。

  • UserDetailsServiceはユーザアカウントを作成
  • PasswordEncoderはパスワードのエンコードとマッチングにBCryptPasswordEncoderを使用
java SpringConfig.java
package com.example.springboot_login.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated() // すべてのリクエストは認証が必要
        ).formLogin(form -> form.loginPage("/login") // ログインページのURL
                .permitAll() // ログインページへのアクセスを許可
                .defaultSuccessUrl("/home", true) // 認証成功後のリダイレクト先を/homeに設定
        ).logout(logout -> logout.logoutUrl("/logout").logoutSuccessUrl("/login?logout"));

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user1 = User.withUsername("user1")
                .password(passwordEncoder().encode("password1")).roles("USER").build();
        UserDetails user2 = User.withUsername("user2")
                .password(passwordEncoder().encode("password2")).roles("USER").build();
        UserDetails admin = User.withUsername("admin")
                .password(passwordEncoder().encode("adminpassword")).roles("ADMIN").build();

        return new InMemoryUserDetailsManager(user1, user2, admin);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

コントローラー

リクエストの受け取るコントローラーの定義

java HomeController.java
package com.example.springboot_login.contoller;

import java.security.Principal;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;


@Controller
public class HomeController {
    @GetMapping("/home")
    public String home(Model model, Principal principal) {
        model.addAttribute("username", principal.getName());
        return "home";
    }

    @GetMapping("/login")
    public String login() {
        return "login"; // login.htmlを返す
    }

    @GetMapping("/logout")
    public String logout(HttpServletRequest request, HttpServletResponse response) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null) {
            new SecurityContextLogoutHandler().logout(request, response, auth);
        }
        return "redirect:/login?logout";
    }

}

HTML

HTMLの定義

html home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <form th:action="@{/login}" method="post">
        <div>
            <label for="username">Username:</label>
            <input type="text" id="username" name="username" />
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" id="password" name="password" />
        </div>
        <div>
            <button type="submit">Login</button>
        </div>
    </form>
    <div th:if="${param.success}">
        <p>Login successful!</p>
    </div>
    <div th:if="${param.logout}">
        <p>You have been logged out.</p>
    </div>
</body>
</html>

html login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Home Page</title>
</head>
<body>
    <h2>Welcome to the Home Page!</h2>
    <p>You have successfully logged in.</p>
    <h1>Welcome, <span th:text="${username}"></span>!</h1>
    <a th:href="@{/logout}">Logout</a>
</body>
</html>

まとめ

SpringSecurityを使用することで、認証処理は自動で行われることになります。認証機能自体の実装をすることなく利用できるため非常に楽かと思います。

サンプルソースについてはGITに公開しているので、参考にしてみてください。
springboot-login

ユーザ情報をDBから取得するして比較したい、ユーザ情報をAPIで取得して比較したい、ユーザの検証はAPIで行っている等、認証経路は色々あると思いますでの、今後ケース別に記事として記載できればと思います。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?