読者です 読者をやめる 読者になる 読者になる

かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その57 )( 気になった点を修正2 )

概要

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その56 )( TableDataAssert クラスの機能追加 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • WebSecurityConfig の DEFAULT_SUCCESS_URL の値を変更する。
    • 画面上部のメニューはログインしたユーザの権限で使用可能なもののみ表示する。
    • セッション用の Cookie 名が JSESSIONID ではなく SESSION になっているので WebSecurityConfig を修正する。

* (2016/03/19追記)セッション用の Cookie 名が JSESSIONID ではなく SESSION になっているのは Spring Session あたりを入れているからではないかと思われます。別に作成している Spring Boot の Web アプリケーションを見てみたら JSESSIONID でした。要注意です。

参照したサイト・書籍

  1. thymeleaf/thymeleaf-extras-springsecurity
    https://github.com/thymeleaf/thymeleaf-extras-springsecurity

目次

  1. WebSecurityConfig の DEFAULT_SUCCESS_URL の値を変更する
  2. 画面上部のメニューはログインしたユーザの権限で使用可能なもののみ表示する
  3. セッション用の Cookie 名が JSESSIONID ではなく SESSION になっているので WebSecurityConfig を修正する

手順

WebSecurityConfig の DEFAULT_SUCCESS_URL の値を変更する

デフォルトの URL は貸出希望書籍 CSV ファイルアップロード画面 ( /booklist ) に変更します。

  1. feature/104-issue ブランチを作成します。

  2. src/main/java/ksbysample/webapp/lending/config の下の WebSecurityConfig.javaリンク先のその1の内容 に変更します。

  3. src/test/java/ksbysample/webapp/lending/web の下の LoginControllerTest.javaリンク先の内容 に変更します。

  4. 動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。

  5. ブラウザを起動し http://localhost:8080/ へアクセスします。ログイン画面が表示されますので、USER_ADMIN 権限を持たないユーザでログインします。ID に "suzuki.hanako@test.co.jp"、Password に "hanako" を入力して、「次回から自動的にログインする」をチェックせずに「ログイン」ボタンをクリックします。

    f:id:ksby:20160314002456p:plain

  6. ログイン後、貸出希望書籍 CSV ファイルアップロード画面が表示されます。

    f:id:ksby:20160314002713p:plain

  7. Ctrl+F2 を押して Tomcat を停止します。

  8. Gradle projects View から clean タスクの実行→「Rebuild Project」メニューの実行→build タスクの実行を行い、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。

    f:id:ksby:20160314003414p:plain

  9. Project View のルートでコンテキストメニューを表示して「Run 'All Tests' with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20160314003818p:plain

  10. commit、GitHub へ Push、feature/104-issue -> 1.0.x へ Pull Request、1.0.x でマージ、feature/104-issue ブランチを削除、をします。

画面上部のメニューはログインしたユーザの権限で使用可能なもののみ表示する

以下の仕様に変更します。

  • メニューは「貸出希望書籍登録」「検索対象図書館登録」の2つだけにする。
  • 「検索対象図書館登録」は ROLE_ADMIN 権限を持つユーザだけ表示する。

実装します。

  1. feature/107-issue ブランチを作成します。

  2. src/main/resources/templates/common の下の mainparts.html を リンク先の内容 に変更します。

  3. 動作確認します。Gradle projects View から bootRun タスクを実行して Tomcat を起動します。

  4. http://localhost:8080/ にアクセスします。ログイン画面が表示されたら ID に "tanaka.taro@sample.com"、Password に "taro" を入力して、「次回から自動的にログインする」をチェックせずに「ログイン」ボタンをクリックします。

    f:id:ksby:20160316233035p:plain

    ROLE_ADMIN 権限を持つユーザなので検索対象図書館登録画面が表示されます。メニューにも「検索対象図書館登録」が表示されることが確認できます。

    f:id:ksby:20160316233146p:plain

  5. ログイン画面に戻り、今度は ID に "suzuki.hanako@test.co.jp"、Password に "hanako" を入力して、「次回から自動的にログインする」をチェックせずに「ログイン」ボタンをクリックします。

    f:id:ksby:20160316233517p:plain

    ROLE_ADMIN 権限を持たないユーザなので貸出希望書籍 CSV ファイルアップロード画面が表示されます。メニューには「検索対象図書館登録」が表示されないことが確認できます。

    f:id:ksby:20160316233704p:plain

  6. Ctrl+F2 を押して Tomcat を停止します。

  7. commit、GitHub へ Push、feature/107-issue -> 1.0.x へ Pull Request、1.0.x でマージ、feature/107-issue ブランチを削除、をします。

セッション用の Cookie 名が JSESSIONID ではなく SESSION になっているので WebSecurityConfig を修正する

Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( 番外編 )( AspectJ でログを出力する )Cookie の値を出力した時に [req][cookie] name = SESSION, value = b264c91f-4b0d-4a2f-8462-b4bdd4b58de2, domain = null, path = null, maxage = -1, secure = false, httponly = false と出力されたのですが、セッション用の Cookie 名が JSESSIONID ではなく SESSION になっていました。

Chrome でも確認しましたが、やっぱり SESSION ですね。いつの間に変わったのでしょうか???

f:id:ksby:20160317000806p:plain

WebSecurityConfig クラスに、ログアウト時に削除する Cookie として JSESSIONID と書いている部分があるので修正します。

  1. feature/117-issue ブランチを作成します。

  2. src/main/java/ksbysample/webapp/lending/config の下の WebSecurityConfig.javaリンク先のその2の内容 に変更します。

  3. Tomcat を起動してログイン、ログアウトが動作することを確認します。(たいした修正ではないので詳細は記述しません)

  4. commit、GitHub へ Push、feature/117-issue -> 1.0.x へ Pull Request、1.0.x でマージ、feature/117-issue ブランチを削除、をします。

ソースコード

WebSecurityConfig.java

■その1

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    public static final String DEFAULT_SUCCESS_URL = "/booklist";
    public static final String REMEMBERME_KEY = "ksbysample-webapp-lending";

  • DEFAULT_SUCCESS_URL の値を /loginsuccess/booklist に変更します。

■その2

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                // .antMatchers("/country/**").permitAll()
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/html/**").permitAll()
                .antMatchers("/encode").permitAll()
                .antMatchers("/urllogin").permitAll()
                .antMatchers("/webapi/**").permitAll()
                .antMatchers("/springMvcMemo/**").permitAll()
                .antMatchers("/textareamemo/**").permitAll()
                .anyRequest().authenticated();
        http.formLogin()
                .loginPage("/")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl(WebSecurityConfig.DEFAULT_SUCCESS_URL)
                .failureUrl("/")
                .usernameParameter("id")
                .passwordParameter("password")
                .successHandler(new RoleAwareAuthenticationSuccessHandler())
                .permitAll()
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/")
                .deleteCookies("JSESSIONID")
                .deleteCookies("remember-me")
                .invalidateHttpSession(true)
                .permitAll()
                .and()
                .rememberMe()
                .key(REMEMBERME_KEY)
                .tokenValiditySeconds(60 * 60 * 24 * 30);
    }
  • .deleteCookies("JSESSIONID").deleteCookies("SESSION") へ変更します。

LoginControllerTest.java

        @Test
        public void 存在するメールアドレスを指定すればログインに成功する() throws Exception {
            // ログイン前にはログイン後の画面にアクセスできない
            mvc.noauth.perform(get(WebSecurityConfig.DEFAULT_SUCCESS_URL))
                    .andExpect(status().isFound())
                    .andExpect(redirectedUrl("http://localhost/"))
                    .andExpect(unauthenticated());

            // 存在するメールアドレスを指定して /urllogin にアクセスすればログインできる
            MvcResult result = mvc.noauth.perform(get("/urllogin?user=" + mvc.MAILADDR_SUZUKI_HANAKO))
                    .andExpect(status().isFound())
                    .andExpect(redirectedUrl(WebSecurityConfig.DEFAULT_SUCCESS_URL))
                    .andExpect(authenticated().withUsername(mvc.MAILADDR_SUZUKI_HANAKO))
                    .andReturn();
            HttpSession session = result.getRequest().getSession();
            assertThat(session).isNotNull();

            // ログイン後の画面にアクセスしてもエラーにならない
            mvc.noauth.perform(get(WebSecurityConfig.DEFAULT_SUCCESS_URL).session((MockHttpSession) session))
                    .andExpect(status().isOk())
                    .andExpect(content().contentType("text/html;charset=UTF-8"))
                    .andExpect(view().name("booklist/booklist"))
                    .andExpect(model().hasNoErrors())
                    .andExpect(authenticated().withUsername(mvc.MAILADDR_SUZUKI_HANAKO));
        }
  • mvc.MAILADDR_TANAKA_TAROmvc.MAILADDR_SUZUKI_HANAKO に変更します。
  • .andExpect(view().name("loginsuccess")).andExpect(view().name("booklist/booklist")) に変更します。

mainparts.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">

..........

                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">メニュー <span class="caret"></span></a>
                            <ul class="dropdown-menu" role="menu">
                                <li><a href="/booklist">貸出希望書籍登録</a></li>
                                <li class="divider" sec:authorize="hasRole('ROLE_ADMIN')"></li>
                                <li sec:authorize="hasRole('ROLE_ADMIN')"><a href="/admin/library">検索対象図書館登録</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>
                <!-- /.navbar-collapse -->
  • html タグに xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3" を追加します。この設定は sec:authorize 等の thymeleaf-extras-springsecurity3 の機能を仕様する html ファイル内にのみ記述すればよく、th:replace で呼び出す側には記述する必要はありません。
  • 以下の4行を削除します。
    • <li><a href="/lendingapp">貸出申請</a></li>
    • <li><a href="/confirmresult">貸出申請結果確認</a></li>
    • <li class="divider"></li>
    • <li><a href="/lendingapproval">貸出承認</a></li>
  • 「検索対象図書館登録」メニューとその上の区切り線の li タグに sec:authorize="hasRole('ROLE_ADMIN')" を追加します。

履歴

2016/03/17
初版発行。
2016/03/19
* 概要に、セッション用の Cookie 名が SESSION になっていることに関するコメントを追記しました。