LoginSignup
6
4

More than 5 years have passed since last update.

Spring Boot + Spring SecurityでURIに認証情報(ユーザ名)を使用したかった話

Last updated at Posted at 2018-06-22

概要

タイトル通りです。
QiitaっぽいURIにしたかったのでやってみました。
ユーザ名をhogeとすると
修正前
http://localhost:8080/menu
修正後
http://localhost:8080/hoge/menu
のようにしたいです。

環境

spring-boot-starter-security: 2.0.2.RELEASE
spring-boot-starter-thymeleaf: 2.0.2.RELEASE
spring-boot-starter-web: 2.0.2.RELEASE
thymeleaf-extras-springsecurity4: 3.0.2.RELEASE
thymeleaf-layout-dialect: 2.3.0

実装

認証処理については偉大な先人の方達の記事を見て実装済みとします。
では、Entityから。

ユーザエンティティ

User.java
@Data
@Entity
public class User implements UserDetails {
    /** ユーザID */
    private String userId;

    /** パスワード */
    private String password;

    /** ユーザ名 */
    private String userName;

// ~省略~

}

ログイン時に遷移するmenu画面用controller

MenuController.java
@Controller
public class MenuController {
    @RequestMapping(value = "{userName}/menu")
    public String menu(@PathVariable("userName") String userName,
            @AuthenticationPrincipal User userDetail) {
        // 認証情報が存在しない場合、ログイン画面にリダイレクト
        if (userDetail == null) {
            return "redirect:login/login";
        }

        // @PathVariableに指定したuserNameを色々使用することも可能
        // System.out.println(userName);

        return "menu";
    }
}

menu画面遷移に使用するheaderテンプレート

header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
  <body>
    <header class="navbar" layout:fragment="header">
      <div class="container">
        <a href="/">
          Home
        </a>
        <a th:href="@{/{userName}/menu(userName=${#authentication.name})}" sec:authorize="isAuthenticated()">
          Menu
        </a>
        <a href="/login" sec:authorize="!isAuthenticated()">
          Login
        </a>
        <a href="/signup" sec:authorize="!isAuthenticated()">
          SignUp
        </a>
        <a href="/logout" th:fragment="logout" sec:authorize="isAuthenticated()">
          Logout
        </a>
      </div>
    </header>
  </body>
</html>

これでMenuのリンクをクリックした際、URIに認証情報.ユーザ名を含めて遷移することができました。
また、認証成功時のリダイレクト先にもユーザ名を含めたい場合ですが、私は下記の方法を使いました。

認証成功時のハンドラ

AuthenticationSuccessHandlerImpl.java
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

    /**
     * 認証成功時の処理
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

        // 認証情報からユーザ名を抜き出し、遷移先のURI情報として使用。
        User userDetail = (User)authentication.getPrincipal();
        String redirectLocation = userDetail.getUserName() + "/menu";

        redirectStrategy.sendRedirect(request, response, redirectLocation);
    }

}

Spring Securityの設定

SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ~省略~

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // アクセス設定
        http.authorizeRequests().antMatchers("/", "/login", "/signup").permitAll()
                .antMatchers("/**").hasRole("USER");

        // ログインの設定
        http.formLogin().loginPage("/login")
                .usernameParameter("userId").passwordParameter("password") 
                .failureHandler(new hogeFailureHandler())
                 // 認証成功時のハンドラ
                .successHandler(new AuthenticationSuccessHandlerImpl())
                .and();

        // ログアウトの設定
        http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout**"))
                .logoutSuccessUrl("/");
    }

// ~省略~
}

まとめ

無事、URIにユーザIDを含めることができるようになりました。
セキュリティ的に問題があるよー
とか
もっと良いやり方があるよー
って人はご指摘頂けるとありがたいです。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4