はじめに
- 試したものは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>