minami1
@minami1

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

spring securityの画面遷移

解決したいこと

FUNCTION1は/user/listに、FUNCTION2は/user/employにそれぞれ画面遷移させたいのですが、usernameとpasswordを正しく入力しても例外の処理にいってしまうので、それを直したい。おそらくFUNCTION1とFUNCTION2を正しく判定できていないのではないかと思います。よろしくお願いします。

発生している問題・エラー

エラー.PNG

該当するソースコード

package com.example.demo.config;

import java.io.IOException;

import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
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;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
				.authorizeHttpRequests(authz -> authz
						.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
						.requestMatchers("/").permitAll()
						.requestMatchers("/user/list").hasRole("FUNCTION1") // /user/listへのアクセスはFUNCTION1の役割が必要
						.requestMatchers("/user/employ").hasRole("FUNCTION2") // /user/employへのアクセスはFUNCTION2の役割が必要
						.anyRequest().authenticated()) // それ以外のリクエストは認証が必要
				.formLogin(formLogin -> formLogin
						.successHandler(authenticationSuccessHandler())) // ログイン成功時のハンドラを設定
				.exceptionHandling(exceptionHandling -> exceptionHandling
						.accessDeniedHandler((request, response, accessDeniedException) -> {
							response.sendRedirect("/");
						})); // アクセス拒否時のハンドラを設定
		return http.build();
	}

	@Bean
	public InMemoryUserDetailsManager userDetailsService() {
		// ユーザー1の設定
		UserDetails user1 = User.withUsername("user1")
				.passwordEncoder(passwordEncoder()::encode) // パスワードのエンコード
				.password("1111") // パスワード
				.roles("FUNCTION1") // ロール(役割)
				.build();

		// ユーザー2の設定
		UserDetails user2 = User.withUsername("user2")
				.passwordEncoder(passwordEncoder()::encode) // パスワードのエンコード
				.password("2222") // パスワード
				.roles("FUNCTION2") // ロール(役割)
				.build();

		return new InMemoryUserDetailsManager(user1, user2);
	}

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

	@Bean
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		return new CustomAuthenticationSuccessHandler();
	}

	// ログイン成功時のハンドラクラス
	private static class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

		@Override
		public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
				Authentication authentication) throws IOException, ServletException {
			if (request.isUserInRole("FUNCTION1")) {
				response.sendRedirect("/user/list"); // FUNCTION1の役割を持つユーザーは/user/listにリダイレクト
			} else if (request.isUserInRole("FUNCTION2")) {
				response.sendRedirect("/user/employ"); // FUNCTION2の役割を持つユーザーは/user/employにリダイレクト
			} else {
				response.sendRedirect("/"); // 上記以外のユーザーはルート(/)にリダイレクト
			}
		}
	}
}

自分で試したこと

自分で調べながら作成したのですがうまく動作しなかったのでよろしくお願いいたします。

0

1Answer

.password("1111") // パスワード

passwordに指定する文字列はPasswordEncoderによりエンコードされたものである必要があります。
なので、

.password(passwordEncoder().encode("1111"))

のようにする必要があるかと思います。

1Like

Comments

  1. @minami1

    Questioner

    返信ありがとうございます。
    エンコードは.password()の上の列で既にエンコードしてあります。
    おそらく原因はonAuthenticationSuccessでFANCTION1,2を呼び出せていないことだと思っています。
    お手数おかけしますが、そこについてのアドバイスを頂けると助かります。

  2. エラーページをよく見るとステータスが404になっているので、
    認証後のリダイレクト先が存在していない可能性があります。

    ブラウザの開発ツールでHTTPリクエストの流れを追ってみてください。
    認証が通るとsendRedirectでステータス302が返ります。
    その後の/user/list/user/employへのリクエストに対し404が返って来ていればリダイレクト先が存在していない(Springに認識されていない)ことになります。
    その場合はControllerが読み込まれている(@ComponentScanなどの対象に入っている)か確認してください。

Your answer might help someone💌