🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Spring Security

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

Java

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

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

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

Q&A

解決済

1回答

2419閲覧

Spring Security ROLEの判断が上手くいかない

shunji2740

総合スコア4

Spring Security

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

Java

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

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

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

0グッド

0クリップ

投稿2020/12/24 02:31

編集2020/12/24 02:39

実現したいこと

Spring Bootを使用し、予約サイトを作っています。
現在Spring Security用のDialectを使用し、sec:authorizeでRoleがADMINまたはログインユーザーIDと予約者のユーザーIDが一致した場合に予約取り消しフォームを表示する機能を実装中です。

発生している問題

ログインユーザーのRoleがADMINでも、予約取り消しフォームが表示されない。一方で、ログインユーザーIDと予約者のユーザーIDが一致した場合は予約取り消しフォームは表示されています。デバックしたところ、RoleにはきちんとADMINがセットされています。エラーメッセージなどは出ていません。

reserveForm.html

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-spring-security5"> <head> <meta charset="UTF-8"> <title th:text="|${#temporals.format(date, 'yyyy/M/d')}の${room.roomName}|"></title> </head> <body th:with="user=${#authentication.principal.user}"> <div> <a th:href="@{'/rooms/' + ${date}}">会議室へ</a> </div> <!-- 予約が出来なかった場合の処理 --> <p style="color: red" th:if="${error != null}" th:text="${error}"></p> <form th:object="${reservationForm}" th:action="@{'/reservations/' + ${date} + '/' + ${roomId}}" method="post"> 会議室: <span th:text="${room.roomName}"></span> <br /> 予約者名: <span th:text="${user.lastName + '' + user.firstName}"></span> <br /> 日付: <span th:text="${#temporals.format(date, 'yyyy/M/d')}"></span> <br /> 時間帯:<select th:field="*{startTime}"> <option th:each="time : ${timeList}" th:text="${time}" th:value="${time}"></option> </select> <span th:if="${#fields.hasErrors('startTime')}" th:errors="*{startTime}" style="color: red">error!</span> <select th:field="*{endTime}"> <option th:each="time : ${timeList}" th:text="${time}" th:value="${time}"></option> <option th:each="time : ${timeList}" th:text="${time}" th:value="${time}"></option> </select> <span th:if="${#fields.hasErrors('endTime')}" th:errors="*{endTime}" style="color: red">error!</span> <br /> <button>予約</button> </form> <!-- 予約済みリスト --> <table> <tr> <th>時間帯</th> <th>予約者</th> <th>操作</th> </tr> <tr th:each="reservation : ${reservations}"> <td><span th:text="${reservation.startTime}"></span> <span th:text="${reservation.endTime}"></span></td> <td><span th:text="${reservation.user.lastName}"></span> <span th:text="${reservation.user.firstName}"></span></td> <td> <form th:action="@{'/reservations/' + ${date} + '/' + ${roomId}}" method="post" sec:authorize="${hasRole('ADMIN') or #vars.user.userId == #vars.reservation.user.userId}"> <input type="hidden" name="reservationId" th:value="${reservation.reservationId}" /> <input type="submit" name="cancel" value="取り消し" /> </form> </td> </tr> </table> </body> </html>

pom.xml

<!-- springsecurity --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency>

ReservationsContoroller.java

package mrs.app.reservation; import java.time.LocalDate; import java.time.LocalTime; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import mrs.domain.model.ReservableRoom; import mrs.domain.model.ReservableRoomId; import mrs.domain.model.Reservation; import mrs.domain.model.User; import mrs.domain.service.reservation.AlreadyReservedException; import mrs.domain.service.reservation.ReservationService; import mrs.domain.service.reservation.UnavailableReservationException; import mrs.domain.service.room.RoomService; import mrs.domain.service.user.ReservationUserDetails; @Controller @RequestMapping("reservations/{date}/{roomId}") public class ReservationsController { @Autowired RoomService roomService; @Autowired ReservationService reservationService; //予約確認・予約一覧画面 //いわゆる確認画面だけでまだ予約は完了していない、予約可能かの確認作業はreserve()にて @RequestMapping(method = RequestMethod.GET) String reserveForm(@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @PathVariable("date") LocalDate date, @PathVariable("roomId") Integer roomId, Model model) { //指定日かつ指定会議室のreservableRoomIdを生成 ReservableRoomId reservableRoomId = new ReservableRoomId(roomId, date); //指定日かつ指定会議室の予約リストを取得 List<Reservation> reservations = reservationService.findReservations(reservableRoomId); //LocalDateオブジェクトを作成してリストに格納する List<LocalTime> timeList = Stream.iterate(LocalTime.of(0, 0), t -> t.plusMinutes(30)) .limit(24 * 2) .collect(Collectors.toList()); model.addAttribute("room", roomService.findMeetingRomm(roomId)); model.addAttribute("reservations", reservations); model.addAttribute("timeList", timeList); //model.addAttribute("user", dummyUser()); return "reservation/reserveForm"; } //予約処理・予約可能かの処理 @RequestMapping(method = RequestMethod.POST) String reserve(@Validated ReservationForm form, BindingResult bindingResult, @AuthenticationPrincipal ReservationUserDetails userDetails, @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @PathVariable("date") LocalDate date, @PathVariable("roomId") Integer roomId, Model model) { if (bindingResult.hasErrors()) { return reserveForm(date, roomId, model); } Reservation reservation = new Reservation(); reservation.setStartTime(form.getStartTime()); reservation.setEndTime(form.getEndTime()); ReservableRoom reservableRoom = new ReservableRoom(new ReservableRoomId(roomId, date)); reservation.setReservableRoom(reservableRoom); //reservation.setUser(dummyUser()); reservation.setUser(userDetails.getUser()); try { //★ここではじめてreservable_roomに登録されているか、重複していないかをチェック reservationService.reserve(reservation); } catch (UnavailableReservationException | AlreadyReservedException e) { model.addAttribute("error", e.getMessage()); return reserveForm(date, roomId, model); } return "redirect:/reservations/{date}/{roomId}"; } //予約削除 @RequestMapping(method = RequestMethod.POST, params = "cancel") String cancel(@RequestParam("reservationId") Integer reservationId, @AuthenticationPrincipal ReservationUserDetails userDetails, @PathVariable("roomId") Integer roomId, @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @PathVariable("date") LocalDate date, Model model) { //ユーザー取得 User user = userDetails.getUser(); try { reservationService.cancel(reservationId, user); } catch (AccessDeniedException e) { //ハンドリングする例外はAccessDeniedException model.addAttribute("error", e.getMessage()); return reserveForm(date, roomId, model); } return "redirect:/reservations/{date}/{roomId}"; } //予約時間のデフォルトForm @ModelAttribute ReservationForm setUpForm() { ReservationForm form = new ReservationForm(); //デフォルト値 form.setStartTime(LocalTime.of(9, 0)); form.setEndTime(LocalTime.of(10, 0)); return form; } }

WebSecurityConfig.java

package mrs; 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.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import mrs.domain.service.user.ReservationUserDetailsService; @Configuration //springsecurityのweb連帯機能(CSRF対策など)を有効にする @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired ReservationUserDetailsService userDetailsService; @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/js/**", "/css/**").permitAll() .antMatchers("/**").authenticated() .and() .formLogin() .loginPage("/loginForm") .loginProcessingUrl("/login") .usernameParameter("username") .passwordParameter("password") .defaultSuccessUrl("/rooms", true) .failureUrl("/loginForm?error=true").permitAll() ; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //指定のUserDetailsServiceとPasswordEncoderを使用して認証を行う auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } }

試したこと

色々と調べてみたところ自分と同じような問題をかかえている方がおり、その人はhasRoleではなくhasAuthorityを使用すると上手く出来たそうです。しかし、自分も試してみましたが上手くいきませんでした。試しにhasRoleにUSERを入れてみましたが、それも上手くいきませんでした。
その後も調べていましたが、解決に至らずここで質問をさせて頂いています。よろしくお願いします。

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

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

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

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

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

guest

回答1

0

自己解決

getAuthorities()の実装にミスがありました。"ROLE_"とすべきところで、アンダーバーが抜けていました。
以下のように実装し直すと正しくROLEの判断が上手くいきました。

@Override public Collection<? extends GrantedAuthority> getAuthorities() { return AuthorityUtils.createAuthorityList("ROLE_" + this.user.getRoleName().name()); }

投稿2020/12/27 10:37

shunji2740

総合スコア4

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問