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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Sendmail

Sendmailは、インターネットで電子メールを送受信するサーバソフトウェア(MTA)です。ユーザーが送信したメールを受け、他メールサーバへ引き渡しバケツリレー式に配送したり、届いたメールをユーザーが受け取るまでの間保管するといった働きをします。

Spring Security

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

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

Spring Boot

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

Q&A

解決済

1回答

1464閲覧

SpringSecurityを使用したログイン機能を実装すると、動作していたメール送信機能が動作しなくなってしまった

hirosan_0116

総合スコア1

Sendmail

Sendmailは、インターネットで電子メールを送受信するサーバソフトウェア(MTA)です。ユーザーが送信したメールを受け、他メールサーバへ引き渡しバケツリレー式に配送したり、届いたメールをユーザーが受け取るまでの間保管するといった働きをします。

Spring Security

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

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

Spring Boot

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

0グッド

0クリップ

投稿2021/06/11 15:00

前提・実現したいこと

Springbootプロジェクトにて、SpringSecurityを使用したログイン機能、
また、フォームからのメール送信機能を持ったアプリを作成しています。

メール送信機能が実装完了後、ログイン機能を実装した所、メール送信が動作しなくなってしまったのを解決したい。

発生している問題・エラーメッセージ

SpringSecurityのログイン機能実装後、フォームからのメール送信が行えなくなってしまった。

該当のソースコード

SendMailController

1@RestController 2public class SendMailController { 3 @Autowired 4 private MailSender mailSender; 5 6 @RequestMapping(value="/sendmail", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE) 7 @ResponseBody 8 public List<String> sendmail(@RequestBody ContactForm form) { 9 String body = "お名前: " + form.getName() + "\n" + 10 "メールアドレス: " + form.getEmail() + "\n" + 11 "メッセージ: \n" + form.getMessage(); 12 SimpleMailMessage msg = new SimpleMailMessage(); 13 msg.setFrom(form.getEmail()); 14 msg.setTo("XXX@gmail.com"); // 適宜変更してください 15 msg.setSubject("お問い合わせがありました"); 16 msg.setText("お問い合わせは下記の通りです。\n\n---------------------------\n" + body + "\n---------------------------"); 17 mailSender.send(msg); 18 return Arrays.asList("OK"); 19 } 20 21} 22

IndexController

1@Controller 2public class IndexController { 3 @GetMapping("/") 4 String index(Model model) { 5 return "index"; 6 } 7 8} 9

indexhtml

1<html xmlns:th="http://www.thymeleaf.org"> 2<head> 3 <meta charset="utf-8"> 4 <link rel="stylesheet" media="all" 5 th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.min.css}"> 6 <script th:src="@{/webjars/jquery/3.3.1-2/jquery.min.js}"></script> 7 <script th:src="@{js/demo.js}"></script> 8 <title>Send email with Spring Boot</title> 9</head> 10<body> 11 <div class="container"> 12 <h1 class="pb-2 mt-4 mb-2 border-bottom border-primary"> 13 お問い合わせ 14 </h1> 15 <div> 16 <p>以下を入力して送信ボタンをクリックしてください。</p> 17 <form name="contactform" id="contactform" role="form"> 18 <div class="form-group"> 19 <label for="inputName" class="col-sm-3">お名前</label> 20 <div class="col-sm-9"> 21 <input type="text" class="form-control" name="name" 22 placeholder="お名前" value=""> 23 </div> 24 </div> 25 <div class="form-group"> 26 <label for="inputEmail" class="col-sm-3">メールアドレス</label> 27 <div class="col-sm-9"> 28 <input type="email" class="form-control" name="email" 29 placeholder="メールアドレス" value=""> 30 </div> 31 </div> 32 <div class="form-group"> 33 <label for="inputMessage" class="col-sm-3">お問い合わせ内容</label> 34 <div class="col-sm-9"> 35 <textarea class="form-control" name="message" rows="5"> 36 </textarea> 37 </div> 38 </div> 39 <div class="text-center"> 40 <button type="button" name="btnSubmit" 41 class="btn btn-success" id="btnSend">送信する</button> 42 </div> 43 </form> 44 </div> 45 </div> 46</body> 47</html>

demojs

1$(document).ready(function() { 2 $('#btnSend').click(function() { 3 $("#btnSend").prop("disabled", true); 4 // フォームのデータをJSONに変換 5 var rawData = $('#contactform').serializeArray(); 6 var data = {}; 7 jQuery.each(rawData, function(i, e) { 8 data[e.name] = e.value; 9 }); 10 // Ajaxを使ってメールを送信 11 $.ajax({ 12 type: "POST", 13 url: "./sendmail", 14 dataType: "json", 15 data: JSON.stringify(data), 16 contentType: 'application/json', 17 scriptCharset: 'UTC', 18 success: function(outdata, dataType) { 19 if (outdata[0] == "OK") alert("メール送信しました"); 20 $("#btnSend").prop("disabled", false); 21 }, 22 error: function(XMLHttpRequest, textStatus, errorThrown) { 23 alert("Error : " + errorThrown); 24 $("#btnSend").prop("disabled", false); 25 } 26 }); 27 }); 28});

WebSecurityConfig

1@Configuration 2@EnableWebSecurity 3public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 4 5 @Autowired 6 private UserDetailsServiceImpl userDetailsService; 7 8 //フォームの値と比較するためにDBから取得したパスワードは、暗号化しているため、フォームの値も暗号化するため利用 9 @Bean 10 public BCryptPasswordEncoder passwordEncoder(){ 11 BCryptPasswordEncoder bCryptPasswordEncoder= new BCryptPasswordEncoder(); 12 return bCryptPasswordEncoder; 13 } 14 @Override 15 public void configure(WebSecurity web) throws Exception{ 16 web.ignoring().antMatchers("/images/**", 17 "/css/**", 18 "/js/**", 19 "template/index.html" 20 ); 21 } 22 23 @Override 24 protected void configure(HttpSecurity http) throws Exception{ 25 http 26 .authorizeRequests() 27 //.antMatchers("/userList").permitAll()//test用(ユーザーリスト)※終わったら消す。 28 .anyRequest().authenticated()//上記以外は全て認証無しの場合アクセス不許可 29 .and() 30 .formLogin() 31 .loginPage("/login") //ログインページはコントローラを経由しないのでViewNameとの紐付けが必要 32 .loginProcessingUrl("/login") //フォームのSubmitURL、このURLへリクエストが送られると認証処理が実行される 33 .usernameParameter("username") //リクエストパラメータのname属性を明示 34 .passwordParameter("password") 35 .defaultSuccessUrl("/userList", true) //認証が成功した際に遷移するURL 36 .failureUrl("/login?error") //認証が失敗した際に遷移するURL 37 .permitAll() //どのユーザでも接続できる。 38 .and() 39 .logout() 40 .logoutUrl("/logout") 41 .logoutSuccessUrl("/login?logout") 42 .permitAll(); 43} 44 45 @Autowired 46 public void configure(AuthenticationManagerBuilder auth) throws Exception{ 47 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 48 } 49 50} 51

試したこと

SpringSecurityを外すとメール送信ができることを確認。

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

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

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

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

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

guest

回答1

0

ベストアンサー

現状だと、"./sendmail"にPOSTリクエストを送るためにもログイン認証が必要になっていることが原因と思われます。
ajaxメソッドでPOSTリクエストをするときにログイン情報が渡っていないため、POSTリクエストが失敗しているのでしょう。
("./sendmail"に限りログインを不要にすることもできますが、メール送信機能であることを考えると不適切と思います)

ここで必要な「ログイン情報」というのは、こちらで試した限り、

  • フォームからの情報送信時に必要な"CSRF-TOKEN"、"XSRF-TOKEN"

の2種類です。(formのaction属性にURLを指定し、submitボタンを押したときには、自動でこれらの情報が渡されるようになっています)

下記のように変更することで動作しないでしょうか??
(追記:ソースの内容を修正しました)

let token = $('input[name="_csrf"]').val(); $.ajax({ type: 'POST', url: './sendmail', dataType: 'json', data: JSON.stringify(data), contentType: 'application/json', scriptCharset: 'UTC', headers: { 'X-CSRF-TOKEN': token, 'X-XSRF-TOKEN': token, }, success: function (outdata, dataType) { if (outdata[0] == 'OK') alert('メール送信しました'); $('#btnSend').prop('disabled', false); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert('Error : ' + errorThrown); $('#btnSend').prop('disabled', false); }, });

投稿2021/06/11 18:18

編集2021/06/12 14:55
hallen0225

総合スコア587

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

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

hirosan_0116

2021/06/12 03:18

ご回答ありがとうございます。 早速試してみましたが、【送信する】ボタン押下後、ボタンがDisable状態になり、そこから何も変化なしになってしまいました。。
hallen0225

2021/06/12 04:44 編集

POSTリクエストの結果はどうなっていますか?? ブラウザの開発者ツール - ネットワークのタブから、Nameが「sendmail」になっている行を探すことで確認できるかと思います。 sendmailの行をクリックすると、「Header」というタブが初期表示されていると思いますので、そこの内容を全て教えてください。
hallen0225

2021/06/12 04:33

また、以前の「メール送信が動作しない」というのはどのような状況だったのでしょうか?? ・「メール送信しました」のアラートは出るが、メールが届かない ・エラーメッセージが書かれたアラートが表示される ・(現状同様)ボタンが無効状態のまま動かない のどれでしょうか?? また、開発者ツールの「Console」のタブにエラーメッセージなどは出ていますか。
hirosan_0116

2021/06/12 06:40

ご丁寧にありがとうございます 開発者ツール-ネットワークタブにおいて、Nameが「sendmail」は存在していません。 存在しているのは、「localhost」「jquery.min.js」「demo.js」「bootstrap.min.js」です。 >また、以前の「メール送信が動作しない」というのはどのような状況だったのでしょうか??   →・エラーメッセージが書かれたアラートが表示される です。 開発者ツールの「Console」タブにエラーメッセージが発生していました。内容は以下です。 demo.js:14 Uncaught TypeError: Cannot read property 'split' of undefined at HTMLButtonElement.<anonymous> (demo.js:14) at HTMLButtonElement.dispatch (jquery.min.js:2) at HTMLButtonElement.y.handle (jquery.min.js:2)
hallen0225

2021/06/12 13:40 編集

Cookieを読み込む処理の部分ですね。ここでCookieを読み込もうとした際に、Cookie自体が存在しないことが原因のようです。 ブラウザの設定でCookieを無効化などしていないでしょうか。 (ネットワークタブに"sendmail"がないのは、そもそもPOSTリクエストを送信する前にエラーになっているためです)
hallen0225

2021/06/12 14:54

大変失礼しました。こちらの認識に間違いがあったようです。 Cookieに'X-XSRF-TOKEN'を保持するためには特別な設定が必要で、WebSecurityConfigを編集する必要がありました。 今回は回答を修正し、demo.jsの修正のみで対応できる方法で考えました。 お手数ですがこちらの内容でもう一度試していただけますでしょうか??
hirosan_0116

2021/06/12 15:45

ありがとうございます 早速試してみましたところ、以下の内容は改善されましたが、状態は初期の以下状態に戻ってしまいました。 ■改善内容   ・【送信する】ボタン押下後、ボタンがDisable状態になり、そこから何も変化なしになってしまった。 ■初期状態   ・エラーメッセージが書かれたアラートが表示される。 ただ、開発者ツール-ネットワークタブにおいて、Name「sendmail」が表示されましたので、そちらを全て記載させていただきます。 Status Codeが403なので、"/sendmail"へのアクセス権がないのかと思い、WebSecurityConfigにて「 http.authorizeRequests().antMatchers("/sendmail").permitAll()」とかも試してみましたが、効果ありませんでした。
hirosan_0116

2021/06/12 15:46

Request URL: http://localhost:8080/sendmail Request Method: POST Status Code: 403 Remote Address: [::1]:8080 Referrer Policy: strict-origin-when-cross-origin Cache-Control: no-cache, no-store, max-age=0, must-revalidate Connection: keep-alive Content-Type: application/json Date: Sat, 12 Jun 2021 15:37:28 GMT Expires: 0 Keep-Alive: timeout=60 Pragma: no-cache Transfer-Encoding: chunked X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Accept: application/json, text/javascript, */*; q=0.01 Accept-Encoding: gzip, deflate, br Accept-Language: ja,en-US;q=0.9,en;q=0.8 Connection: keep-alive Content-Length: 60 Content-Type: application/json Cookie: JSESSIONID=5D9F0971A11DD61A72B9B83CEF2E7030 Host: localhost:8080 Origin: http://localhost:8080 Referer: http://localhost:8080/ sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91" sec-ch-ua-mobile: ?0 Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 X-Requested-With: XMLHttpRequest {name: "admin", email: "xxx@yahoo.co.jp", message: "aiueo"} email: "xxx@yahoo.co.jp" message: "aiueo" name: "admin"
hallen0225

2021/06/12 22:45

POST時に'X-CSRF-TOKEN'、'X-XSRF-TOKEN'(認証に必要な情報)が渡っていないようですね。 これらに格納する値を"$('input[name="_csrf"]').val();"で取得しているのですが、開発者ツールのElementタブで見たときに、name: "_csrf"のinput要素は生成されているでしょうか? (これがSpring Securityで自動生成されている想定なのですが)
hirosan_0116

2021/06/13 00:04

確認してみましたが、Elementsタブで見たときに、name: "_csrf"のinput要素は生成されていませんでした。
hallen0225

2021/06/13 03:57

それでしたら、HTMLのformタグ内に下記の行を追加してください(本来生成されるはずの行なのですが) <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
hirosan_0116

2021/06/13 05:29

ありがとうございます! 試したら無事に解決しました! 原因と解決策は以下の認識ですが、あっていますでしょうか? ■原因 フォームからの情報送信時に、SpringSecurityのCSRF対策で必要な"CSRF-TOKEN"、"XSRF-TOKEN"が不足していた。   ※formのaction属性にURLを指定してsubmitボタンを押したときは、自動でこれらの情報が渡される仕組みになっている。 ■解決策 ・tokenを取得し、HEADERの"CSRF-TOKEN"、"XSRF-TOKEN"に取得したtokenを設定してあげる。   ※本来であれば上記で改善するはずですが、私の場合tokenが取得できていなかった為、formタグ内でtokenを渡してやる処理を追加することで改善。
hallen0225

2021/06/14 04:15

はい、大体合っています。 ただ、解決策の、 > 私の場合tokenが取得できていなかった為、formタグ内でtokenを渡してやる処理を追加することで改善。 の部分に少々語弊があります。 「tokenが取得できていなかった」ではなく、「HTML上にCSRF-TOKENが入っているinput要素が生成されていなかった」ことが原因です。 恐らく、この状態だと、formのaction属性にURLを指定してsubmitボタンを押した際も、CSRF-TOKENがないのでPOSTに失敗していたと思われます。
hirosan_0116

2021/06/14 11:45

なるほど。 何故「HTML上にCSRF-TOKENが入っているinput要素が生成されていなかった」のか。は、また自分で調べてみようかと思います。 掲題の件に関してはおかげで解決しましたし、色々と勉強になりました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問