Spring Securityを利用する

2022.02.25

参考:http://terasolunaorg.github.io/guideline/current/ja/Security/Authentication.html

参考:https://codezine.jp/article/detail/11703

参考:https://spring.pleiades.io/projects/spring-security#learn

利用の開始

依存関係を追加する

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-security'
}

この状態で全てのルートでログインが必須になります

画像

設定

WebSecurityConfigurerAdapterを継承したクラスを作成して、デフォルトbasic設定の書き換えを行います。

“/”はログイン不要でアクセスできるようにして、それ以外は認証必須としてみます。

package com.volkruss.misaka.web.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll() // "/"のアクセスは全て許可する
                .anyRequest().authenticated() // 設定してないリクエストは認証が必要とする
                ;
    }

}

DB認証をする

データーベースに登録されているユーザー情報でログインできるようにします。

UserDetailsServiceを実装したクラスにloadUserByUsernameメソッドをオーバーライドしてDBからユーザーを取得してorg.springframework.security.core.userdetails.Userクラスを返却します。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // dbからユーザーを取得する
        User user = this.userRepository.findByUserName(username);

        // ユーザーの権限を取得する
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("USER"));

        // TODO 継承したログインユーザークラスの作成と返却を行う
        return new org.springframework.security.core.userdetails.User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),authorities);
    }
}

設定クラスのメソッドを修正します。ログインページまで見えなくなっているので、ログインページはアクセスできるようにします

@Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll() // "/"のアクセスは全て許可する
                .anyRequest().authenticated() // 設定してないリクエストは認証が必要とする
                // 以下修正(追加)
                .and()
                .formLogin()
                .and()
                .logout()
                .permitAll();
        http.httpBasic();
    }

この状態でログイン画面(“/login”)からデータベースに登録しているユーザー名とパスワードでログインすると、ホーム画面に遷移でき、他のルートもアクセスできるようになります。

ロールの取得

現在はUSERロールを手動で付けていますが、こちらもデータベースから取得するようにします。

データベースから取得したロール情報からSimpleGrantedAuthorityを作成してGrantedAuthorityコレクションにaddします。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // dbからユーザーを取得する
        User user = this.userRepository.findByUserName(username);

        // ユーザーの権限を取得する
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        //authorities.add(new SimpleGrantedAuthority("USER"));

        List<Role> roles = this.roleRepository.getRoleByUserId(user.getId());

        roles.forEach(role -> {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        });

        // TODO 継承したログインユーザークラスの作成と返却を行う
        return new org.springframework.security.core.userdetails.User(user.getUsername(), new BCryptPasswordEncoder().encode(user.getPassword()), authorities);
    }

}
@Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll() // "/"のアクセスは全て許可する
                .antMatchers("/system/**").hasRole("SYSTEM") // SYSTEMロールを持つユーザーのみ参照可能
                .antMatchers("/admin/**").hasRole("ADMIN") // ADMINロールを持つユーザーのみ参照可能
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .logout()
                .permitAll();
        http.httpBasic();
    }

ADMINロールあり

画像

SYSTEMロールなし

画像

ロールによってページの参照権を操作できるようになります。