FrontPage > Spring Bootの覚書 > Spring Security

データーベースを使用した認証

1. 組み込みデータベース(HSQLDB)を使用する場合

  • build.gradleファイルのdependenciesにspring-boot-starter-jdbcと
    hsqldbを追加し、プロジェクト右クリック[Gradle]->[Refresh All]を選択。

    (build.gradle抜粋)
    dependencies {
       compile("org.springframework.boot:spring-boot-starter-jdbc")
       compile("org.springframework.boot:spring-boot-starter-web")
       compile("org.springframework.boot:spring-boot-starter-thymeleaf")
       compile("org.springframework.security:spring-security-web:3.2.5.RELEASE")
       compile("org.springframework.security:spring-security-config:3.2.5.RELEASE")
       compile ('org.thymeleaf.extras:thymeleaf-extras-springsecurity3:2.1.1.RELEASE')
       runtime("org.hsqldb:hsqldb")
       providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
       testCompile("org.springframework.boot:spring-boot-starter-test")
    }
  • WebSecurityConfigクラスにプロパティとしてdataSourceを追加。

    (src/main/java/com/ziqoo/sbSample/WebSecurityConfig.java抜粋)
    @Configuration
    @EnableWebMvcSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
       @Autowired
       private DataSource dataSource;
  • さらにconfigureGlobalメソッドを以下のように修正する。

    (src/main/java/com/ziqoo/sbSample/WebSecurityConfig.java抜粋)
       @Autowired
       public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
           auth
               .jdbcAuthentication()
                   .dataSource(dataSource)
                   .withDefaultSchema()
                   .withUser("user3").password("naisho").roles("USER").and()
                   .withUser("user4").password("naisho").roles("ADMIN");
       }

2. 外部データベースを使用する場合

今回はHSQLDBを別途インストールしdevdbという名称でデータベースを作成。 サーバーモードで起動している。

  • データベースにusersとauthoritiesテーブルを作成する。

    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);
  • 作成したテーブルに認証情報を登録する。

    (usersテーブル)
    sst-users.png

    (authoritiesテーブル)
    sst-authorities.png
  • データーソースを設定する。
    データベースの接続情報をapplication.propertiesに記述する。

    (src/main/resources/application.properties抜粋)
    spring.datasource.driver-class-name=org.hsqldb.jdbcDriver
    spring.datasource.url=jdbc:hsqldb:hsql://localhost/devdb
    spring.datasource.username=sa
    spring.datasource.password=
  • WebSecurityConfigクラスのconfigureGlobalメソッドを以下のように修正。

    (src/main/java/com/ziqoo/sbSample/WebSecurityConfig.java抜粋)
       @Autowired
       public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
           auth
               .jdbcAuthentication()
                   .dataSource(dataSource);
       }

3. 認証情報に独自テーブルを使用する場合

例えば以下のようなテーブルを使用する場合

(USER_INFOテーブル)

sst-user_info.png


(USER_ROLESテーブル)

sst-user_roles.png


  • WebSecurityConfigクラスのconfigureGlobalメソッド内でqueryを追加。
       @Autowired
       public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
           auth
               .jdbcAuthentication()
                   .dataSource(dataSource)
                   .authoritiesByUsernameQuery("select user_id as username, role as authority from user_roles where user_id = ?")
                   .usersByUsernameQuery("select user_id as username, paswd as password, true as enabled from user_info where user_id = ?")
                   ;
       }

ログイン情報に項目を追加する場合

上記USER_INFOテーブルのORG_NAMEをログイン情報に追加してみる。

  • 追加する項目ORG_NAMEを保持するUserDetailsクラス(ログイン情報)を新たに作成する。

    (例 src/main/java/com/ziqoo/sbSample/security/MyUserDetails.java)
    package com.ziqoo.sbSample.security;
    
    import java.util.List;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import com.ziqoo.sbSample.model.UserInfo;
    public class MyUserDetails extends User {
       private final String orgName;
    
       public MyUserDetails(UserInfo userInfo, List<? extends GrantedAuthority> authorityList) {
           super(userInfo.getUserId(), userInfo.getPaswd(), true, true, true, true, authorityList);
           this.orgName = userInfo.getOrgName();
       }
    
       public String getOrgName() {
           return orgName;
       }
    }
    ここで、UserInfoクラスは下記問い合わせの結果を保持しているものとする。
    select i.USER_ID, i.PASWD, i.ORG_NAME, r.USER_ID R_USER_ID, r.ROLE
    from USER_INFO i join USER_ROLES r on i.USER_ID = r.USER_ID
    where i.USER_ID = ?

    (src/main/java/com/ziqoo/sbSample/model/UserInfo.java抜粋)
    package com.ziqoo.sbSample.model;
    
    import java.util.List;
    
    public class UserInfo {
       private String userId;
       private String paswd;
       private String orgName;
       private List<UserRoles> userRolesList;
    
    // 以下getter, setter 省略
    (src/main/java/com/ziqoo/sbSample/model/UserRoles.java抜粋)
    package com.ziqoo.sbSample.model;
    public class UserInfo {
       private String userId;
       private String role;
    
    // 以下getter, setter 省略
  • UserDetailsを取得するUserDetailsServiceを作成する。

    (例 src/main/java/com/ziqoo/sbSample/security/MyUserDetailsService.java)
    package com.ziqoo.sbSample.security;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    
    import com.ziqoo.sbSample.model.UserInfo;
    import com.ziqoo.sbSample.model.UserRoles;
    import com.ziqoo.sbSample.service.UserInfoService;
    
    public class MyUserDetailsService implements UserDetailsService {
       @Autowired
       private UserInfoService userInfoService;
    
       @Override
       public UserDetails loadUserByUsername(String username)
               throws UsernameNotFoundException {
    
           UserInfo userInfo = userInfoService.selectDetailByUserId(username);
           if (userInfo == null) {
               throw new UsernameNotFoundException("");
           }
    
           List<SimpleGrantedAuthority> authorityList = new ArrayList<SimpleGrantedAuthority>();
    
           List<UserRoles> roles = userInfo.getUserRolesList();
           for (UserRoles role: roles) {
               authorityList.add(new SimpleGrantedAuthority(role.getRole()));
           }
           return new MyUserDetails(userInfo, authorityList);
       }
    }
    ここで、UserInfoServiceはユーザ情報を検索し結果をUserInfoへ設定して返すものとする。

  • 作成したMyUserDetailsServiceを登録するためにWebSecurityConfigの、configureGlobalメソッドを以下のように修正する。

    (src/main/java/com/ziqoo/sbSample/WebSecurityConfig.java抜粋)
       @Autowired
       public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
           auth.userDetailsService(myUserDetailsService());
       }
    
       @Bean
       public UserDetailsService myUserDetailsService() {
           return new MyUserDetailsService();
       }

ログイン情報へのアクセス

  • コントロールクラスからアクセスする場合、メソッドの引数に。Principalを指定する。
    例として管理者ページ用のコントロールクラスを作成し、アクセスしてみる。
    MvcConfigクラスに追加した管理者ページ用ビューコントローラの記述を削除し、
    新たにAdminPageControllerクラスを作成する。

    (src/main/java/com/ziqoo/sbSample/MvcConfig.java抜粋)
       @Override
       public void addViewControllers(ViewControllerRegistry registry) {
           registry.addViewController("/login").setViewName("login");
           registry.addViewController("/").setViewName("top");
           registry.addViewController("/input").setViewName("input");
           registry.addViewController("/user/sample").setViewName("user/userSample");
    //        registry.addViewController("/admin/sample").setViewName("admin/adminSample");
       }

    (src/main/java/com/ziqoo/sbSample/web/AdminPageController.java)
    package com.ziqoo.sbSample.web;
    
    import java.security.Principal;
    
    import org.springframework.security.core.Authentication;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import com.ziqoo.sbSample.security.MyUserDetails;
    
    @Controller
    @RequestMapping("/admin")
    public class AdminPageController {
       private static final Logger log = LoggerFactory.getLogger(AdminPageController.class);
     
       @RequestMapping("/sample")
       public String adminSample(Principal principal, Model model) {
           Authentication auth = (Authentication)principal;
           MyUserDetails userDetails = (MyUserDetails)auth.getPrincipal();
    
           log.info(userDetails.getUsername()+":"+userDetails.getAuthorities()+":"+ userDetails.getOrgName());
    
           return "admin/adminSample";
       }
    }
  • 画面からアクセスする場合は以下のように、"sec:authentication"を使用する。

    (src/main/resources/templates/admin/adminSample.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">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Insert title here</title>
    <link th:href="@{/resources/css/base.css}" rel="stylesheet"
     type="text/css" />
    </head>
    <body>
     <p>このページは管理者ページです。</p>
     <a th:href="@{/}">トップページ</a>
     <p />
     <table border="1">
       <tr>
         <th>user</th>
         <td sec:authentication="name"></td>
       </tr>
       <tr>
         <th>roles</th>
         <td sec:authentication="principal.authorities"></td>
       </tr>
       <tr>
         <th>組織名</th>
         <td sec:authentication="principal.orgName"></td>
       </tr>
     </table>
    </body>
    </html>
    ssdb-adminPg.png



添付ファイル: filessdb-adminPg.png 573件 [詳細] filesst-user_info.png 537件 [詳細] filesst-user_roles.png 534件 [詳細] filesst-authorities.png 534件 [詳細] filesst-users.png 591件 [詳細]

トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-03-06 (金) 01:02:32 (1376d)