Spring Securityでログイン画面を管理者とユーザーで分けて作成したい。
実現したいこと
現在、下記のことを実装したいと考えていますがうまくいきません。
Spring Securityのバージョンが6になり、最新情報がなかなか見つからず困っております。
アドバイスを頂けると助かります。
- 管理者側のログイン画面とユーザーログイン画面を別々で用意する。
- ログインに成功すると管理者用のトップ画面とユーザー用のトップ画面に遷移する。
- 管理者はどちらのログイン画面からもログインでき、どちらの機能も使用することができる。
- ユーザ側が管理者画面からログインしようとすると、ユーザーのログイン画面に遷移する。
発生している問題・エラー(長いため最初のほうをコピーして貼り付けています。)
- 管理者ログイン機能の/admin/loginからはログインすることが可能。
しかし、ユーザーも/admin/loginからログインすることができてしまう。
ログイン成功時は、管理者は管理者用トップ画面に遷移。ユーザーはユーザーのトップ画面に遷移。 - ユーザーログイン機能の/user/loginからはログインすることができない。
下記のPOSTに関するエラーが出てしまう。
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Jul 26 10:40:36 JST 2023
There was an unexpected error (type=Method Not Allowed, status=405).
Method 'POST' is not supported.
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported
at org.springframework.web.servlet.support.WebContentGenerator.checkRequest(WebContentGenerator.java:381)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:164)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365)
at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at
WARN[0;39m [35m212088[0;39m [2m---[0;39m [2m[nio-8080-exec-8][0;39m [36m.w.s.m.s.DefaultHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported]
または、問題・エラーが起きている画像をここにドラッグアンドドロップ
該当するソースコードJava
WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig {
@Autowired
private AdminLoginUserDetailsService adminLoginUserDetailsService;
@Autowired
private UserLoginUserDetailsService userLoginUserDetailsService;
// ログイン成功後のリダイレクト先を設定
@Bean
AuthenticationSuccessHandler successHandler() {
return new SimpleUrlAuthenticationSuccessHandler() {
@Override
protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
// ログインユーザーのロールを取得する
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String role = auth.getAuthorities().toString();
// デフォルトのリダイレクト先
String targetUrl = "/login?error";
if(role.contains("ROLE_ADMIN")) {
if(request.getRequestURI().equals("/admin/login")) {
targetUrl = "/admin/notices";
} else {
targetUrl = "/user/login";
}
} else if(role.contains("ROLE_USER")) {
targetUrl = "/user/notices";
}
return targetUrl;
}
};
}
// 管理者ログイン用のセキュリティ設定
@Bean
@Order(1)
SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/admin/login", "/user/login").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginProcessingUrl("/admin/login")
.usernameParameter("empNum")
.loginPage("/admin/login")
.successHandler(successHandler())
.permitAll()
)
.userDetailsService(adminLoginUserDetailsService)
.logout((logout) -> logout.permitAll());
return http.build();
}
// ユーザーログイン用のセキュリティ設定
@Bean
@Order(2)
SecurityFilterChain userSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/user/login", "/admin/login").permitAll()
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.requestMatchers(HttpMethod.POST, "/user/login").permitAll()
.anyRequest().authenticated()
)
.formLogin((login) -> login
.loginProcessingUrl("/user/login")
.usernameParameter("empNum")
.loginPage("/user/login")
.successHandler(successHandler())
.permitAll()
)
.userDetailsService(userLoginUserDetailsService)
.logout((logout) -> logout.permitAll());
return http.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
下記が入りきらなかったコードです。
https://docs.google.com/document/d/1UJP3j2WizmekwzwpLtu94nyzeRJaSXi-6DA06L3osAE/edit?usp=sharing
自分で試したこと
LoginUserDetalisとServiceを1つでやっていたが、管理者とユーザーで分けて作成した。
.requestMatchers(HttpMethod.POST, "/user/login").permitAll()を追加したり、.userDetailsService(userLoginUserDetailsService)で指定したりした。
WebSecurityConfigを管理者とユーザーで分けたり、1つにしたりした。
Spring Securityの過去の記事を参考に、下記のサイトで書き換えたがうまくいかない状態。
https://qiita.com/suke_masa/items/908805dd45df08ba28d8
###補足情報
Java17
Eclipse2023 Full edition
Spring Boot 3.1.1
Spring Security 6
0 likes