質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Spring Security

Spring Securityは、Springのサブプロジェクトの一つでWebアプリケーションに必要な機能を追加します。正規ユーザーであるかを確認するための「認証機能」と、ユーザーのアクセスを制御する「認可機能」を簡単に追加することが可能です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

解決済

2回答

4213閲覧

spring securityを使用してファイルアップロード

sakura2685

総合スコア20

Spring Security

Spring Securityは、Springのサブプロジェクトの一つでWebアプリケーションに必要な機能を追加します。正規ユーザーであるかを確認するための「認証機能」と、ユーザーのアクセスを制御する「認可機能」を簡単に追加することが可能です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

1グッド

1クリップ

投稿2020/09/20 05:15

SprngBootを使用してWebアプリケーションを作成しています。
ファイルアップロード機能を実装したいのですが、SpringSecurityを使用していることで403エラーとなってしまいます。

エラーメッセージ:
There was an unexpected error (type=Forbidden, status=403).

MultipartFilterを登録することで解決できるとドキュメントにはあるのですが解決できませんでした…
https://spring.pleiades.io/spring-security/site/docs/current/reference/html5/#servlet-csrf-considerations-multipart

問題解決のためにサンプルアプリを作成しなおして動作を確認してみましたが、SpringSecurityを導入するとやはりエラーになります。

わかるかたいらっしゃれば回答よろしくお願いいたします。

index

1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org/"> 3<head> 4<meta charset="UTF-8"> 5<title>ファイルアップロードのサンプル</title> 6</head> 7<body> 8<p th:if="${error}" th:text="${error}">エラーメッセージ</p> 9<form action="/upload" method="post" enctype="multipart/form-data"> 10 アップロードするJPEGファイルを選択してください<br> 11 <input type="file" name="file" accept="image/jpeg"> 12 <input type="submit"> 13</form> 14<p> 15 <img src="/images/picture.jpg"> 16</p> 17<p><a href="/test">テストページへ</a></p> 18</body> 19</html>

Sample05Application

1package com.example.demo; 2 3import java.io.File; 4 5import org.springframework.boot.SpringApplication; 6import org.springframework.boot.autoconfigure.SpringBootApplication; 7import org.springframework.context.annotation.Bean; 8 9@SpringBootApplication.java 10public class Sample05Application { 11 12 public static void main(String[] args) { 13 SpringApplication.run(Sample05Application.class, args); 14 } 15 16 @Bean 17 public AppConfig appConfig() { 18 // Webアプリケーションはアプリケーション実行ディレクトリとは別のディレクトリで実行される 19 // 起動時のディレクトリをAppConfigのimageDirフィールドに保持しておく 20 File imageDir = new File("images"); 21 imageDir = imageDir.getAbsoluteFile(); 22 23 // imagesフォルダがなかったら作成する 24 if (!imageDir.exists()) { 25 imageDir.mkdir(); 26 } 27 28 AppConfig appConfig = new AppConfig(); 29 appConfig.setImageDir(imageDir); 30 return appConfig; 31 } 32} 33

Sample05Controller

1package com.example.demo; 2 3import java.io.File; 4import java.io.IOException; 5 6import org.springframework.beans.factory.annotation.Autowired; 7import org.springframework.stereotype.Controller; 8import org.springframework.ui.Model; 9import org.springframework.web.bind.annotation.GetMapping; 10import org.springframework.web.bind.annotation.PostMapping; 11import org.springframework.web.bind.annotation.RequestParam; 12import org.springframework.web.multipart.MultipartFile; 13 14@Controller 15public class Sample05Controller { 16 17 @Autowired 18 private AppConfig appConfig; 19 20 @GetMapping("/") 21 public String index() { 22 return "index"; 23 } 24 25 @PostMapping("/upload") 26 public String upload(@RequestParam MultipartFile file, Model model) { 27 // ファイルを選択せずにフォームを送信したかの確認 28 if (file.isEmpty()) { 29 model.addAttribute("error", "ファイルを指定してください"); 30 return "index"; 31 } 32 33 // アップロードされたファイルを指定の名前で保存 34 File dest = new File(appConfig.getImageDir(), "picture.jpg"); 35 try { 36 file.transferTo(dest); 37 } catch (IllegalStateException e) { 38 // TODO 自動生成された catch ブロック 39 e.printStackTrace(); 40 } catch (IOException e) { 41 // TODO 自動生成された catch ブロック 42 e.printStackTrace(); 43 } 44 return "index"; 45 } 46 47 @GetMapping("/test") 48 public String test() { 49 return "testpage"; 50 } 51 52} 53

AppConfig

1package com.example.demo; 2 3import java.io.File; 4 5import lombok.Data; 6 7@Data 8public class AppConfig { 9 private File imageDir; 10}

WebSecurityConfig

1package com.example.demo; 2 3import org.springframework.security.config.annotation.web.builders.HttpSecurity; 4import org.springframework.security.config.annotation.web.builders.WebSecurity; 5import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 6import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 8@EnableWebSecurity 9public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 10 11 @Override 12 public void configure(WebSecurity web) { 13 web.ignoring().antMatchers("/css/**", "/html/**", "/images/**"); 14 } 15 16 @Override 17 protected void configure(HttpSecurity http) throws Exception { 18 19 http.authorizeRequests().antMatchers("/").permitAll(); 20 } 21}

■以下、multipartfilter設定。
②も試しましたがダメでした…

SecurityWebApplicationInitializer

1package com.example.demo; 2 3import java.util.EnumSet; 4 5import javax.servlet.DispatcherType; 6import javax.servlet.ServletContext; 7 8import org.springframework.core.annotation.Order; 9import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; 10import org.springframework.web.multipart.support.MultipartFilter; 11 12public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer{ 13// @Override …⓶ 14// protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { 15// System.out.println("secチェック"); 16// final MultipartFilter multipartFilter = new MultipartFilter(); 17// servletContext.addFilter("multipartFilter", multipartFilter) 18// .addMappingForUrlPatterns( 19// EnumSet.allOf(DispatcherType.class), false, "/*"); 20// } 21 @Override 22 protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { 23 insertFilters(servletContext, new MultipartFilter()); 24 } 25} 26

■spring.web を使用しているためweb.xmlがないので以下を記述
参考:http://taktos.hatenablog.com/entry/2014/05/16/Spring_Security%E3%81%AECSRF%E5%AF%BE%E7%AD%96%E3%81%A8Servlet_3.0%E3%81%AEMultipart%E3%82%92Java_Config%E3%81%A7%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B

WebAppInitializer

1package com.example.demo; 2 3import javax.servlet.MultipartConfigElement; 4import javax.servlet.ServletRegistration.Dynamic; 5 6import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 7 8public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 9 10 @Override 11 protected void customizeRegistration(Dynamic registration) { 12 System.out.println("webチェック"); 13 registration.setMultipartConfig(new MultipartConfigElement( 14 System.getProperty("java.io.tmpdir"), -1, -1, 1024 * 1024)); 15 } 16 17 @Override 18 protected Class<?>[] getRootConfigClasses() { 19 return new Class[] {AppConfig.class}; 20 } 21 22 @Override 23 protected Class<?>[] getServletConfigClasses() { 24 return new Class[] {WebConfig.class}; 25 } 26 27 @Override 28 protected String[] getServletMappings() { 29 return new String[] {"/"}; 30 } 31}
kumaGoro_95👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

csrfの設定が必要です。

html

1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org/"> 3<head> 4<meta charset="UTF-8"> 5<title>ファイルアップロードのサンプル</title> 6</head> 7<body> 8<p th:if="${error}" th:text="${error}">エラーメッセージ</p> 9<form action="/upload" method="post" enctype="multipart/form-data"> 10 アップロードするJPEGファイルを選択してください<br> 11 <input type="file" name="file" accept="image/jpeg"> 12 <input type="hidden" 13 th:name="${_csrf.parameterName}" 14 th:value="${_csrf.token}"/> 15 <input type="submit"> 16</form> 17<p> 18 <img src="/images/picture.jpg"> 19</p> 20<p><a href="/test">テストページへ</a></p> 21</body> 22</html>

spring security

投稿2020/09/27 10:01

wyq2020

総合スコア60

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakura2685

2020/09/28 13:07

おぉ…できました。トークンを実際に含めるやり方だとこんなにあっさりできるんですね。 試していませんでした(汗) 推奨アプローチとされるMultipartFilterの方は分かりますでしょうか…?
wyq2020

2020/09/28 15:00

Spring bootを使用すると、MultipartFilterが必要ないと思います。
wyq2020

2020/09/28 15:44

MultipartFilterの設定は何のためでしょうか?
sakura2685

2020/09/30 13:54

spring bootを使うとmultipartfilterは必要ないんですね…。調べるポイントが間違っていました。。 csrfトークンが原因ともっと早く気づけていれば… 本当に助かりました。この度はありがとうございました!m(_ _)m
guest

0

ベストアンサー

Controllerの @PostMapping("/upload") に対するSpringSecurityの設定がないので「認証が必要」なURLになります。

SpringSecurityの設定を拝見した限りでは、ログイン(認証)画面の設定がありませんので、/upload も permitAllのURLに追加するか、ログインの設定をしてください。

類似する質問が直近でありますので参考に。

https://teratail.com/questions/293177

投稿2020/09/22 06:57

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakura2685

2020/09/24 12:43

A-pZ様 回答ありがとうございます! URLの件、失礼しました…。以下に修正しました。 http.authorizeRequests().antMatchers("/**").permitAll(); しかし結果は変わらずでした。 参考URLも読んでみて(休日にもっとじっくり用んでみようと思います)、WebSecurityまわりでは特に差異はないと思うのですが、アップロードの時点でエラーになってしまうのはなぜなのでしょうか…
A-pZ

2020/09/26 04:59

設定で追加されている WebAppInitializerの一部や、SecurityWebApplicationInitializer は不要ではないかと存じます(試してはいませんが…この設定は現在だと不要です)
sakura2685

2020/09/27 01:58

SecurityWebApplicationInitializerを削除しました! WebAppInitializerについてはどの部分が不要になりますでしょうか? getRootConfigClasses、getServletConfigClasses、getServletMappingsはオーバーライドを強制されているのでcustomizeRegistrationについてのことかな?と思いコメントアウトしましたが結果は変わらずでした… そもそもデバッグ用に入れてある System.out.println("webチェック"); がコンソールで出力されないので、このクラス自体が読み込まれていない、もしくは読み込まれる前にエラーになっているのではと疑っています。。
A-pZ

2020/09/27 07:09

お返事ありがとうございます。 なるほど、WebAppInitializerが反応していない…のであればそれも削除しても問題ないかと。(というのも、私の方では、これらのInitializerは定義していません。) .antMatchers()の内容も特に問題ありませんですし、その他のSpringSecurityに関する設定では特に問題ないように思えますので、念のため画像アップロードのHTMLテンプレートも確認させてください。
sakura2685

2020/09/28 13:10

画像アップロードのHTMLテンプレートはindex.htmlになります!(質問ではindexと表示されています) wyq2020様の回答のおかげでいったんはアップロードできたのですが、可能であればmultipartfilterの設定方法も教えていただけるとありがたいです…。
A-pZ

2020/09/28 13:41

なるほど、CSRFチェックをわざわざ入れないと動作しない原因があります。 action="/upload" ではなく、th:action="@{/upload}" とすると、自動的にCSRFトークンの隠し入力パラメータが生成されます。これは https://github.com/thymeleaf/thymeleaf-extras-springsecurity/ の機能です。 multipart-Filterは特に不要だと思いますが(本質問中にも見つかっていませんが…)もしその場合は別途質問を挙げた方が良いかもしれません。
sakura2685

2020/09/30 13:48

あぁ…thymeleafの機能が使えてなかったんですね! 無事アップロードできました。 multipartfilterは、multipartのデータを送信する際にはspringsecurity filterchainの前に設定する必要があるとドキュメントで読んだのでこの設定とばかり思っていました。 深読みして深読みした結果、初歩的なお話でお恥ずかしい。 本当に助かりました!ありがとうございますm(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問