Spring bootでweb セキュリティ(ログイン認証)編

65
セキュリティ(ログイン認証)編
  • date post

    16-Jan-2017
  • Category

    Engineering

  • view

    10.399
  • download

    5

Transcript of Spring bootでweb セキュリティ(ログイン認証)編

Page 1: Spring bootでweb セキュリティ(ログイン認証)編

セキュリティ(ログイン認証)編

Page 2: Spring bootでweb セキュリティ(ログイン認証)編

アジェンダ はじめに 準備 認証方式 ユーザー認証処理 ユーザー認証処理のカスタマイズ パスワードエンコード BCryptを使ったパスワードのハッシュ化 ロール ユニットテスト 静的コンテンツの配置 まとめ

Page 3: Spring bootでweb セキュリティ(ログイン認証)編

はじめに Spring Securityを用いたログイン認証について説明する

Page 4: Spring bootでweb セキュリティ(ログイン認証)編

はじめに 使用ライブラリ&バージョン

■Spring Security 4.0

Page 5: Spring bootでweb セキュリティ(ログイン認証)編

準備 Maven依存関係

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>

Page 6: Spring bootでweb セキュリティ(ログイン認証)編

準備 設定用クラスの作成

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { }

設定クラスであることを @Configurationアノテーションで明記 WebMvcSecurityの有効化

既存のAdapterを拡張

Page 7: Spring bootでweb セキュリティ(ログイン認証)編

準備 設定用クラスの作成

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { }

このクラスに様々な設定を記述する

Page 8: Spring bootでweb セキュリティ(ログイン認証)編

認証方式・ユーザー認証処理 認証方式とユーザー認証処理を組み合わせる

■認証方式 BASIC認証、Form認証

■ユーザー認証処理(何を基にユーザー認証をするか) インメモリ(プログラム内固定)、 データベース、LDAP など

Page 9: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 設定メソッドの上書き

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { } }

configureメソッドをオーバーライドし、 引数のHttpSecurityに対して 様々な設定を行う

Page 10: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 アクセス出来るURLの範囲を決める

@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated(); }

HttpSecurityから、 アクセス範囲を決めるクラスを取得

ルート「/」は全ユーザーが アクセス可能

他のURLは認証が必要

Page 11: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 BASIC認証を使用する

@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated() .and() .httpBasic(); }

BASIC認証を使用する

Page 12: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ここまでの状態を試す

http://localhost:8080/test http://localhost:8080/sample

その他のURLでは 全て認証を求められる BASIC認証をするよう実装したので BASIC認証の画面が出る

http://localhost:8080/

ルートURLは全ユーザーが アクセス可能 (ただし今は未実装なので Not Foundエラーになる)

Page 13: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 以下の画面遷移でForm認証を使用する

ホーム画面

挨拶画面

【Click here】クリック

参考:Securing a Web Application http://spring.io/guides/gs/securing-web/

URL: /

URL: /hello

Page 14: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 以下の画面遷移でForm認証を使用する

ホーム画面

挨拶画面

【Click here】クリック

参考:Securing a Web Application http://spring.io/guides/gs/securing-web/

URL: /

URL: /hello http .authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated();

下のアクセス制御により、ルート「/」は 全ユーザーがアクセス出来るので 問題なく表示される

ただしルート「/」以外は 認証が必要になる。

Page 15: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 以下の画面遷移でForm認証を使用する

ホーム画面

挨拶画面

【Click here】クリック

参考:Securing a Web Application http://spring.io/guides/gs/securing-web/

URL: /

URL: /hello

ログイン画面

そのため実際は 間にログイン画面が挟まる

Page 16: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ホーム画面を作成する

<!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"> <head> <title>Spring Security Example</title> </head> <body> <h1>Welcome!</h1> <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p> </body> </html>

home.html

Page 17: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ホーム画面を作成する

home.html

Page 18: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 挨拶画面を作成する

<!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"> <head> <title>Hello World!</title> </head> <body> <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1> <form th:action="@{/logout}" method="post"> <input type="submit" value="Sign Out"/> </form> </body> </html>

hello.html

ログインしたユーザー名が 埋め込まれる

Page 19: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 挨拶画面を作成する

hello.html

ログインしたユーザー名が 埋め込まれる

Page 20: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 URLとビューを関連付ける

@Configuration public class MvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/home").setViewName("home"); registry.addViewController("/").setViewName("home"); registry.addViewController("/hello").setViewName("hello"); } }

本来はコントローラを作成してビューを制御するが、 今回は簡易版としてWebMvcConfigurerAdapterを 拡張してURLとビューのテンプレートをお手軽に関連付ける

/home もしくは / は home.html を /hello は hello.html を表示する

Page 21: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 設定メソッドを変更する

@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated() .and() // .httpBasic(); .formLogin() .loginPage("/login_page") .usernameParameter("username") .passwordParameter("password") .permitAll(); }

BASIC認証をやめて Form認証を行う 認証のページは /login_page

ユーザー名とパスワードの項目は username と password

全ユーザーのアクセスを許可する

Page 22: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 URLとビューを関連付ける

@Configuration public class MvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/home").setViewName("home"); registry.addViewController("/").setViewName("home"); registry.addViewController("/hello").setViewName("hello"); registry.addViewController("/login_page").setViewName("login_page"); } }

ログインページ用の関連付けを追加

Page 23: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ログイン画面を作成する

<!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"> <head> <title>Spring Security Example </title> </head> <body> <form th:action="@{/login_page}" method="post"> <div><label> User Name : <input type="text" name="username"/> </label></div> <div><label> Password: <input type="password" name="password"/> </label></div> <div><input type="submit" value="Sign In"/></div> </form></body></html>

login_page.html

ユーザー名とパスワードの項目は username と password

Page 24: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ログイン画面を作成する

login_page.html

Page 25: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ユーザー認証処理に、インメモリ認証を使用する

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { ~~ 中略 ~~ } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { } } HttpSecurityを引数に受けるconfigureメソッドの他に

AuthenticationManagerBuilderを受け取るメソッドがあり、 ユーザー認証処理はここに設定を記述する

Page 26: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 ユーザー認証処理に、インメモリ認証を使用する

@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER").and() .withUser("admin").password("password").roles("USER", "ADMIN"); } }

インメモリ認証を行う指定

ユーザーは、user と admin の2つを用意する。 パスワードはいずれも password で、 ロールは user が USERで、adminは USER と ADMIN。 (ロールについては後ほど)

Page 27: Spring bootでweb セキュリティ(ログイン認証)編

認証方式 動作確認

http://localhost:8080/ user / password を入力

userが表示される

admin / password を入力 admin が表示される

Page 28: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理 データベース登録したにログイン情報で認証処理を試す

Page 29: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理 接続先をapplication.ymlに記述する

spring: datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://xxx.xxx.xxx.xxx/database username: databaseusername password: xxx

接続先に応じて変更を!

Page 30: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理 ユーザー認証処理をJDBC方式にする

@Autowired private DataSource dataSource; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth // .inMemoryAuthentication() // .withUser("user").password("password").roles("USER").and() // .withUser("admin").password("password").roles("USER", "ADMIN"); .jdbcAuthentication() .dataSource(dataSource); } }

コンテナが管理している 接続先情報を取得

JDBC方式を指定する

接続先を指定する

Page 31: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理 デフォルトのユーザー情報テーブル

create table users( username varchar_ignorecase(50) not null primary key, password varchar_ignorecase(50) not null, enabled boolean not null ); create table authorities ( username varchar_ignorecase(50) not null, authority varchar_ignorecase(50) not null, constraint fk_authorities_users foreign key(username) references users(username) ); create unique index ix_auth_username on authorities (username,authority);

■Spring Security Reference - 37.1 User Schema より http://docs.spring.io/spring-security/site/docs/4.0.3.CI-SNAPSHOT/reference/htmlsingle/#user-schema

Page 32: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理 テスト用のユーザーを登録

insert into users values('test_user', 'test', true); insert into authorities values('test_user', 'ROLE_USER');

Page 33: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理 動作確認

http://localhost:8080/ test_user / test を入力

test_userが 表示される

Page 34: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ 自前の認証処理を実装する

create table user_info ( username varchar(50) not null primary key, email varchar(50) not null, password varchar(50) not null, enabled boolean not null, authority varchar(50) not null ); create unique index ix_user_info_email on user_info (email);

以下のテーブルに登録したユーザー情報で認証する

テーブルを新規作成

メールアドレスを登録し、 この値とパスワードで 認証する

insert into user_info values('test_user', 'test@user', 'test', TRUE, 'ROLE_USER');

サンプルデータ

Page 35: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ ユーザー情報用のエンティティを作成する

@Data @NoArgsConstructor @AllArgsConstructor @Entity @Table(name="user_info") public class UserInfo { @Id @GeneratedValue private String username; @Column(nullable = false) private String email; @Column(nullable = false) private String password; @Column(nullable = false) private Boolean enabled; @Column(nullable = false) private String authority;

Lombokを使用

user_infoテーブルの エンティティとして宣言

カラムに応じた フィールドを宣言

Page 36: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ ユーザー情報用のエンティティを作成する

@Data @NoArgsConstructor @AllArgsConstructor @Entity @Table(name="user_info") public class UserInfo implements UserDetails { ~~ 中略 ~~ public Collection<GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority(authority)); return authorities; }

UserDetailsに定義された メソッドを実装 (他も同様に)

Spring Securityの決まりに従って UserDetailsを実装

Page 37: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ ユーザー情報用のリポジトリを作成する

public interface UserInfoRepository extends JpaRepository<UserInfo, String> { public UserInfo findByEmail(String email); }

メールアドレスで検証する メソッドを宣言 (実装はJPAに任せる)

先ほどのエンティティを扱うリポジトリ

Page 38: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ 自前の認証処理を実装したServiceクラスを作成する

@Service public class UserInfoService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { return null; } }

UserDetailsServiceを 実装する

UserDetailsServiceに 定義されているメソッドを実装する

InMemoryUserDetailsManagerなど 既存の認証処理はこのインターフェースを 実装している

Page 39: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ 自前の認証処理を実装したServiceクラスを作成する

@Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { if (s==null || "".equals(s)) { throw new UsernameNotFoundException("Username is empty"); } UserInfo userInfo = userInfoRepository.findByEmail(s); if (userInfo == null) { throw new UsernameNotFoundException( "User not found for name: " + s); } return userInfo; }

未入力はエラー

入力されたメールアドレスで検索

検索できなかった場合はエラー

検索できたらそれを返す

Page 40: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ Serviceクラスを使用して認証するよう設定する

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserInfoService userInfoService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userInfoService); // .jdbcAuthentication() // .dataSource(dataSource); }

作成したServiceクラスを宣言

JDBC認証から、 作成したServiceクラスでの 認証に切り替える

Page 41: Spring bootでweb セキュリティ(ログイン認証)編

ユーザー認証処理のカスタマイズ 動作確認

http://localhost:8080/ test@user / test を入力

test_userが 表示される

認証はメールアドレス で行う

ログイン後は ユーザー名を表示

Page 42: Spring bootでweb セキュリティ(ログイン認証)編

パスワードエンコード パスワードを平文のまま保存するのは危険なのでエンコードして保存し、 認証時に入力されたパスワードをエンコードしてチェックする

ログイン画面

平文パスワード

エンコード処理

エンコード済み パスワード

データベース

読み込み処理

エンコード済み パスワード

認証

エンコード済みの パスワードを格納

Page 43: Spring bootでweb セキュリティ(ログイン認証)編

パスワードエンコード ハッシュ値が入るようテーブルを変更

create table user_info ( username varchar(50) not null primary key, email varchar(50) not null, password varchar(60) not null, enabled boolean not null, authority varchar(50) not null ); create unique index ix_user_info_email on user_info (email);

以下のテーブルに登録したユーザー情報で認証する

insert into user_info values('test_user', 'test@user', '$2a$10$fms1eItee/kPxD8FSdnk/uO9bC.CBweUrQE.CLRgZgzIGcFJVcLRu', TRUE, 'ROLE_USER');

サンプルデータ

パスワードのカラムを拡張

「test」のハッシュ値

Page 44: Spring bootでweb セキュリティ(ログイン認証)編

パスワードエンコード 認証プロバイダを変更

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserInfoService userInfoService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .authenticationProvider(createAuthProvider()); // .userDetailsService(userInfoService); // .jdbcAuthentication() // .dataSource(dataSource); } 作成したServiceクラスでの認証から、

後述する認証プロバイダに変更する

Page 45: Spring bootでweb セキュリティ(ログイン認証)編

パスワードエンコード 認証プロバイダを変更

auth .authenticationProvider(createAuthProvider()); // .userDetailsService(userInfoService); // .jdbcAuthentication() // .dataSource(dataSource); } private AuthenticationProvider createAuthProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userInfoService); authProvider.setPasswordEncoder(new BCryptPasswordEncoder()); return authProvider; }

認証プロバイダの作成

認証処理を実装した Serviceクラスを指定する

パスワードのエンコードに BCryptエンコーダを使用する

Page 46: Spring bootでweb セキュリティ(ログイン認証)編

BCryptを使った パスワードのハッシュ化 BCryptのハッシュ値

$2a$10$fms1eItee/kPxD8FSdnk/uO9bC.CBweUrQE.CLRgZgzIGcFJVcLRu

BCryptのハッシュ値

insert into user_info values('test_user', 'test@user', '$2a$10$fms1eItee/kPxD8FSdnk/uO9bC.CBweUrQE.CLRgZgzIGcFJVcLRu', TRUE, 'ROLE_USER');

サンプルデータ BCryptでハッシュ化したパスワード

ヘッダ ソルト値 22文字 ハッシュ値 32文字

Page 47: Spring bootでweb セキュリティ(ログイン認証)編

BCryptを使った パスワードのハッシュ化 BCryptのヘッダ

$2a$10$fms1eItee/kPxD8FSdnk/uO9bC.CBweUrQE.CLRgZgzIGcFJVcLRu

ヘッダ ソルト値 22文字 ハッシュ値 32文字

2a →

10 →

バージョン番号。 主流は「2a」。

ストレッチング(ハッシュ値の計算を繰り返す)回数の指定。 累乗数を指定する。 10の場合、210なので1,024回繰り返す。

Page 48: Spring bootでweb セキュリティ(ログイン認証)編

BCryptを使った パスワードのハッシュ化 BCryptのソルト値

$2a$10$fms1eItee/kPxD8FSdnk/uO9bC.CBweUrQE.CLRgZgzIGcFJVcLRu

ヘッダ ソルト値 22文字 ハッシュ値 32文字

指定のソルト値とパスワードを基に 指定のストレッチ回数で求めたハッシュ値。

Page 49: Spring bootでweb セキュリティ(ログイン認証)編

BCryptを使った パスワードのハッシュ化 BCryptのハッシュ値

$2a$10$fms1eItee/kPxD8FSdnk/uO9bC.CBweUrQE.CLRgZgzIGcFJVcLRu

ヘッダ ソルト値 22文字 ハッシュ値 32文字

ハッシュ値を求める際に自動生成されるソルト値。

Page 50: Spring bootでweb セキュリティ(ログイン認証)編

BCryptを使った パスワードのハッシュ化 Spring SecurityでのBCryptのハッシュ値の生成方法

String hashedPassword = BCrypt.hashpw( rawPassword, BCrypt.gensalt() );

ハッシュ化前のパスワード ソルト値の生成

ハッシュ化したパスワード

BCryptクラスを使用

Page 51: Spring bootでweb セキュリティ(ログイン認証)編

BCryptを使った パスワードのハッシュ化 Spring SecurityでのBCryptのハッシュ値の生成方法

String hashedPassword = BCrypt.hashpw( “testpassword”, BCrypt.gensalt() );

上記コードを3回実行した結果

$2a$10$UmuUZJ4D6IaJMm5.UQdsAef2fz6QQuRyRDYrSFab4uNv2SzNEHFW2 $2a$10$.XMgSGCnfecWXh25jKDoZOojlyaMWODJxpoCcOh0YorGM53Vcxq22 $2a$10$1Cc9rpBWu5NenpYameu2f.nHohPeo0HfRLn7dAwKnhQMLkNdibOd6

「testpassword」のハッシュ値を取得するコード

ソルト値もハッシュ値も違う 3つの値が生成された

Page 52: Spring bootでweb セキュリティ(ログイン認証)編

ロール Spring Securityのユーザごとの権限に応じたアクセス制御

UserDetails

GrantedAuthority

1

0..*

ユーザー名等の情報を保持

そのユーザーの 権限情報を保持

権限情報は 複数持てる 権限情報に応じた

アクセス制御を行う

Page 53: Spring bootでweb セキュリティ(ログイン認証)編

ロール サンプルのテーブル構成と実装

create table user_info ( username varchar(50) not null primary key, email varchar(50) not null, password varchar(50) not null, enabled boolean not null, authority varchar(50) not null );

以下のテーブルに登録したユーザー情報で認証する

サンプルのテーブルは 1ユーザー1権限

権限を保持するカラム

public class UserInfo implements UserDetails { ~~ 中略 ~~ public Collection<GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority(authority)); return authorities; }

標準モデルに合わせて リストで返却

Page 54: Spring bootでweb セキュリティ(ログイン認証)編

ロール サンプルユーザー

insert into user_info values('test_user', 'test@user', 'xxx', TRUE, 'ROLE_USER'); insert into user_info values('admin_user', 'admin@user', 'xxx', TRUE, 'ROLE_ADMIN');

サンプルのユーザー 一般権限ユーザー

管理者権限ユーザー

Page 55: Spring bootでweb セキュリティ(ログイン認証)編

ロール アクセス出来るURLの範囲を変更する

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated(); ~~中略~~

「/admin/」内のURLは 管理者権限ユーザーのみが アセス出来る

Page 56: Spring bootでweb セキュリティ(ログイン認証)編

ロール 動作確認

管理者ユーザーで ログイン

管理者のみのURLへ アクセス可能

一般ユーザーで ログイン 管理者ではないので

「403 Forbidden」 (閲覧禁止)が返ってくる

Page 57: Spring bootでweb セキュリティ(ログイン認証)編

ユニットテスト MockMVCを利用してテストを行う

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @SpringApplicationConfiguration(classes = App.class) public class AppTest { @Autowired private WebApplicationContext context; private MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders .webAppContextSetup(context) .build(); }

Page 58: Spring bootでweb セキュリティ(ログイン認証)編

ユニットテスト MockMVCにSpring Securityの利用を通知

import static org.springframework.security.test.web.servlet.setup. SecurityMockMvcConfigurers.*; ~~中略~~ public void setup() { mockMvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); }

MockMVCに通知

Page 59: Spring bootでweb セキュリティ(ログイン認証)編

ユニットテスト ログインしないでアクセスするテスト

@Test public void ログインせずにルートページへアクセス() throws Exception { mockMvc.perform(get("/")) .andExpect(status().isOk()); } @Test public void ログインせずにハローページへアクセス() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().is3xxRedirection()); }

ログインせずにルートへアクセスする場合は OKステータスが返ってくる

ログインせずにハローページへアクセスする場合は 300番台(移動通知)のどれか (正確には302:Moved Temporarily)が 返ってくる

Page 60: Spring bootでweb セキュリティ(ログイン認証)編

ユニットテスト ログインしてアクセスするテスト

@Test @WithMockUser(username="test@user") public void ログインしてハローページへアクセス() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()); }

ログインするユーザを 「WithMockUser」アノテーションで指定

ログインした後なら OKステータスが返ってくる

Page 61: Spring bootでweb セキュリティ(ログイン認証)編

ユニットテスト 権限を指定してアクセスするテスト

@Test @WithMockUser(username="user@user", roles="USER") public void 一般ユーザーで管理者ページへアクセス() throws Exception { mockMvc.perform(get("/admin/adminPage")) .andExpect(status().is4xxClientError()); } @Test @WithMockUser(username="admin@user", roles="ADMIN") public void 管理者ーザーで管理者ページへアクセス() throws Exception { mockMvc.perform(get("/admin/adminPage")) .andExpect(status().isOk()); }

「WithMockUser」アノテーションに 権限を記述

一般ユーザーには権限がないので 400番台(処理失敗)のどれか (正確には403:Forbidden)が返ってくる

管理者ユーザーならアクセス可能

Page 62: Spring bootでweb セキュリティ(ログイン認証)編

ユニットテスト Formログインにアクセスするテスト

@Test public void ログインページのテスト() throws Exception { mockMvc.perform( formLogin() .user("username", "test@user") .password("password", "test") .loginProcessingUrl("/login_page") ).andExpect(status().isFound()) .andExpect( authenticated() .withUsername("test_user") .withRoles("USER") ); }

Formログインをする

認証に成功し、 ユーザー名とロールが想定通りか チェックする

認証情報(今回はメアド)、 パスワード、ログインURLを指定

Page 63: Spring bootでweb セキュリティ(ログイン認証)編

静的コンテンツの配置 ログイン前でも画像・CSS・JavaScript等は参照可能とする

<div><input type="submit" value="Sign In"/></div> </form> <img src="/img/test.png"/>

ログイン前は何も設定しないと、 静的コンテンツにアクセス出来ない

静的コンテンツは resources/static に配置

Page 64: Spring bootでweb セキュリティ(ログイン認証)編

静的コンテンツの配置 ログイン前でも画像・CSS・JavaScript等は参照可能とする

@Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**", "/js/**", "/img/**"); }

除外リストに静的コンテンツを記述

ログイン前でも静的コンテンツへの アクセスが行えるようになった

Page 65: Spring bootでweb セキュリティ(ログイン認証)編

まとめ 参考

■Spring Security Reference http://docs.spring.io/spring-security/site/docs/4.0.3.CI-SNAPSHOT/reference/htmlsingle/ ■Spring Bootでユーザ認証 | memorandum http://ksoichiro.blogspot.jp/2015/03/spring-boot.html ■Spring Boot でログイン画面 + 一覧画面 + 登録画面の Webアプリケーションを作る ( その10 )( ログイン画面作成3 ) - かんがるーさんの日記 http://ksby.hatenablog.com/entry/2015/02/08/030648#LoginControllerTest.java ■BCrypt(Blowfish暗号)について調べたので文書化してみました http://www.kamiya54.info/post/100503173956/bcryptblowfish%E6%9A%97%E5%8F%B7%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%AA%BF%E3%81%B9%E3%81%9F%E3%81%AE%E3%81%A7%E6%96%87%E6%9B%B8%E5%8C%96%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F