LoginSignup
11
20

More than 3 years have passed since last update.

spring boot security + DB認証を試した時のポイント

Last updated at Posted at 2019-10-07

はじめに

  • 試したものはspring securityのサンプルにDBからのユーザ検索を追加した形になります
  • 記載していないところ(htmlとか)はサンプルそのまま使用しています
  • プロジェクトはSpring Initializrで作成します
  • DBはPostgreSQLを使用します

Spring securityの初期設定

WebSecurityConfigurer.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        // テストのためパスワードの暗号化はしない
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // spring securityで無視するリクエストパスを設定
        web.ignoring().antMatchers("/css/**", "/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // ログイン処理の認証ルールを設定
        http.authorizeRequests()
                .antMatchers("/", "/login").permitAll() // 認証なしでアクセス可能なパス
                .anyRequest().authenticated() // それ以外は認証が必要
                .and()
            .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login") // ログインフォームのアクションに指定したURL[action="@{/login}"]を設定
                .usernameParameter("username") // ログインフォームのユーザー欄のname属性を設定
                .passwordParameter("password") // ログインフォームのパスワード欄のname属性を設定
                .successForwardUrl("/home") // ログイン成功時に遷移するURL
                .failureUrl("/login?error") // ログイン失敗時に遷移するURL
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .permitAll()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
    }
}

ログインURLのマッピング

  • WebMvcConfigurerインターフェースを実装したクラスに書く必要がある
WebConfig.java
@Configuration
public class WebConfig implements WebMvcConfigurer {
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
    }
}

認証後のURLのマッピング

  • 認証情報(UserModel)は引数のAuthenticationから取得可能
DemoController.java
@Controller
public class DemoController {
    @RequestMapping(value = {"/", "/home"})
    public String home() {
        return "home";
    }

    @RequestMapping(value = "/hello")
    public String hello(Authentication authentication, Model model) {
        // 認証情報を取得
        UserModel userModel = (UserModel)authentication.getPrincipal();
        model.addAttribute("name", userModel.getName());

        return "hello";
    }
}

ここからDB認証部分の実装になります

  • やることはDB検索して結果を返すだけなので簡単です

DB接続情報の設定

application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.driver-class-name=org.postgresql.Driver

ログインユーザの情報を格納するテーブルを作成

  • データは適当に追加して下さい
create table t_user (
  id character varying(10) not null
  , name character varying(100) not null
  , password character varying(500) not null
  , enabled boolean DEFAULT true
  , primary key (user_id)
);

認証情報を格納するBeanの作成

  • ユーザーネームに該当するものがIDになるので、メソッド[getUsername]にはidを返すようにしています
UserModel.java
@NoArgsConstructor
@AllArgsConstructor
@Data
public class UserModel implements UserDetails {

    private String id;

    private String name;

    private String password;

    private boolean enabled;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.id;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return this.enabled;
    }

}

ログインユーザを取得するSQL

UserRepository.xml
<mapper namespace="com.example.demo.UserRepository">
  <select id="selectByUser" parameterType="com.example.demo.UserRepository" resultType="com.example.demo.UserModel">
    SELECT id, name, password, enabled FROM t_user where id = #{id};
  </select>
</mapper>

ログインユーザを取得するSQLのインターフェース

UserRepository.java
@Mapper
public interface UserRepository {
    public UserModel selectByUser(String username);
}

認証情報を検索する

  • UserDetailsServiceインターフェースのloadUserByUsernameでDB検索するだけ
UserDetailsServiceImpl.java
@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (StringUtils.isEmpty(username)) throw new UsernameNotFoundException("");

        UserModel userModel = userRepository.selectByUser(username);

        // ユーザが存在しない場合
        if (userModel == null) throw new UsernameNotFoundException("");
        // アカウントの有効期限切れ、アカウントのロック、パスワードの有効期限切れ、ユーザの無効を判定
        if (!userModel.isAccountNonExpired() || !userModel.isAccountNonLocked() ||
                !userModel.isCredentialsNonExpired() || !userModel.isEnabled())
            throw new UsernameNotFoundException("");
        return userModel;
    }

}

ここまで出来れば、あとはアプリを実行するだけでDB認証が試せます

その他 ハマったこと

  • 画面を表示しようとしたら[Circular view path [login]]が発生
    • 原因:Spring Initializrでプロジェクトを作成していたため、pom.xmlにthymeleafを追加していなかった
    • 対処方法:pom.xmlに下記を追加
pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
11
20
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
11
20