riku__02
@riku__02

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Spring bootのSecurity(認可設定)についての質問

解決したいこと

現在解体新書という書籍にて11章のSpring セキュリティのURLの認可という内容に着手しています。
管理者ユーザにてのみ閲覧可能である、アドミン専用画面を作成しましたが、アドミンユーザでログイン後遷移すると500エラーが発生しています。
管理者以外のユーザで遷移すると403エラーに飛ぶのでこちらは正しいと思っています。
解決方法の指摘ございましたら、アドバイス頂きたいです。よろしくお願いいたします。

例)
Ruby on RailsでQiitaのようなWebアプリをつくっています。
記事を投稿する機能の実装中にエラーが発生しました。
解決方法を教えて下さい。

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

image.png

■ADMINユーザにてログインし、遷移画面
image.png
SQLログ
image.png

■ADMIN以外のユーザにてログイン後遷移画面
image.png

例)

今回修正したソース

■admin.html(新規追加)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/layout}">

<head>
	<title>アドミン権限専用</title>
</head>

<body>
	<div layout:fragment="content">
		<div class="header border-bottom mt-2">
			<h1 class="h2">アドミン権限専用画面</h1>
		</div>
	</div>
</body>
</html>

■AdminController.java(新規追加)

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;

public class AdminController {

	/** アドミン権限専用画面に遷移 */
	@GetMapping("/admin")
	public String getAdmin() {
		return "admin/admin";
	}
}

■menu.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout}" xmlns:sec="http://www.thymeleaf.org/extrans/spring-security">
<head>
</head>

<body>
	<div layout:fragment="menu" class="bg-light">
		<ul class="nav nav-pills nav-stacked">
			<li role="presentation">
				<a class="nav-link" th:href="@{'/user/list'}">ユーザ一覧</a>
			</li>
			<li role="presentation" sec:authorize="hasRole('ADMIN')">
				<a class="nav-link" th:href="@{'/admin'}">アドミン専用</a>
			</li>
		</ul>
	</div>
</body>

</html>

■SecurityConfig.java

package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;

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.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
public class SecurityConfig {
	
	@Autowired
	private UserDetailsService userDetailsService;

	// パスワードの暗号化
	@Bean
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/** セキュリティの対象外を設定 */
	@Bean
	public WebSecurityCustomizer webSecurityCustomizer() {
		return web -> web.ignoring().requestMatchers(
				new AntPathRequestMatcher("/webjars/**"), new AntPathRequestMatcher("/css/**"),
				new AntPathRequestMatcher("/js/**"), new AntPathRequestMatcher("/h2-console/**"));
	}

	/** セキュリティの各種設定 */
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

		// ログイン不要ページの設定
		http
				.authorizeHttpRequests()
				.requestMatchers("/login").permitAll() //直リンクOK
				.requestMatchers("/user/signup").permitAll() //直リンクOK
				.requestMatchers("/admin").hasAnyAuthority("ROLE_ADMIN")//権限制御
				.anyRequest().authenticated(); // それ以外は直リンクNG

		//ログイン処理
		http.formLogin()
				.loginProcessingUrl("/login")//ログイン処理のパス
				.loginPage("/login")//ログインページの指定
				.failureUrl("/login?error")//ログイン失敗時の遷移先
				.usernameParameter("userId")//ログインページのユーザーID
				.passwordParameter("password")//ログインページのパスワード
				.defaultSuccessUrl("/user/list", true);//成功後の遷移先
		
		//ログアウト処理
		http.logout()
		.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
		.logoutUrl("/logout")
		.logoutSuccessUrl("/login?logout");

		// CSRF対策を無効に設定(一時的)
		//http.csrf().disable();

		return http.build();
	}

    /** 認証の設定 */
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        PasswordEncoder encoder = passwordEncoder();
        // インメモリ認証
        /*
        auth
            .inMemoryAuthentication()
                .withUser("user") // userを追加
                    .password(encoder.encode("user"))
                    .roles("GENERAL")
                .and()
                .withUser("admin") // adminを追加
                    .password(encoder.encode("admin"))
                    .roles("ADMIN");
        */

        // ユーザーデータ認証
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(encoder);
    }
}

自分で試したこと

まずADMINユーザ等でログインできなかったので、パスワードをハッシュ化し、改善しました。その後管理者ユーザでもログインできないことを発覚しました。
管理者以外のユーザだと403エラーなので管理者ユーザであることは認識されていそうです。認可設定をqiita等で調べていますが、上手く解消と至っていません・

0

1Answer

入れ違いとなってしまったようですのでこちらにも投稿します。

類似のエラーについて問題解決しているサイトを見る限り、favicon.icoが適切な場所に置かれていない、
或いはfavicon.icoへの静的アクセスがSpring Securityの機能によって弾かれているのが原因ではないでしょうか。

貴方のプロジェクト内で/resources/static配下の任意の場所にfavicon.icoが配置されていることを確認の上、

com.example.demo.config.SecurityConfig.javaに以下のように追記してみてください。

    /** セキュリティの対象外を設定 */
	@Bean
	public WebSecurityCustomizer webSecurityCustomizer() {
		return web -> web.ignoring().requestMatchers(
				new AntPathRequestMatcher("/webjars/**"), new AntPathRequestMatcher("/css/**"),
				new AntPathRequestMatcher("/js/**"), new AntPathRequestMatcher("/h2-console/**"),
+               new AntPathRequestMatcher("/favicon.ico")
                 );
	}
0Like

Comments

  1. @riku__02

    Questioner

    @tomdog735さん
    先ほどはログインの件アドバイス頂きありがとうございました!
    私のプロジェクト内で/resources/static配下の任意の場所にfavicon.icoはないんですよね、、
    書籍の中でもでてこなくて用意したがよいですかね。。確認してみます。
    image.png

  2. @riku__02
    失礼いたしました。
    質問に載せていただいたコードを見て気付いたことですが、
    新規追加されたAdminController.javaにアノテーション@Controllerを付与されていますでしょうか。
    もしされてないようでしたらお試しください。

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    
    + @Controller
    public class AdminController {
    
    	/** アドミン権限専用画面に遷移 */
    	@GetMapping("/admin")
    	public String getAdmin() {
    		return "admin/admin";
    	}
    }
    
  3. @riku__02

    Questioner

    @tomdog735
    ありがとうございます。。。
    @Controllerの付け忘れでした。。
    付与してあげたところ、無事に管理者ユーザにて専用画面に遷移することが出来ました。
    大変助かりましたとともに、アドバイス本当にありがとうございました。
    このような簡単な間違えは2度しないよう履歴に残す形で進めていきます。
    image.png

Your answer might help someone💌