Spring Bootで独自の認証を組み込む
認証を独自に実装したい
DBの認証やアルゴリズムがちょっと特殊な場合など
今回やったこと
・AuthenticationProviderを実装したAuthenticationProviderImplクラスを作成してここで認証を実施
・WebSecurityConfigurerAdapterにAuthenticationProviderImplを設定する
独自認証実装
AuthenticationProviderImpl.java
package com.example.config; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; import com.example.entity.User; @Component public class AuthenticationProviderImpl implements AuthenticationProvider { private static final Logger logger = LoggerFactory.getLogger(AuthenticationProviderImpl.class); @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { // ユーザーとパスワードを取得 String id = auth.getName(); String password = auth.getCredentials().toString(); // 未設定の場合はエラー if ("".equals(id) || "".equals(password)) { // 例外はSpringSecurityにあったものを適当に使用 throw new AuthenticationCredentialsNotFoundException("ログイン情報に不備があります。"); } // 認証情報を取得 User user = authCheck(id, password); if (user == null) { throw new AuthenticationCredentialsNotFoundException("ログイン情報が存在しません。"); } // トークンを返却 return new UsernamePasswordAuthenticationToken(user, password, auth.getAuthorities()); } @Override public boolean supports(Class<?> token) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(token); } @SuppressWarnings({ "unchecked", "rawtypes" }) private User authCheck(String username, String password) { User user = null; List<Map<String, String>> list = new ArrayList<>(); Map map; map = new HashMap<String, String>(){ private static final long serialVersionUID = 1L; {put("username", "admin");} {put("password", "password");} {put("role", "ADMIN");} }; list.add(map); map = new HashMap<String, String>(){ private static final long serialVersionUID = 1L; {put("username", "user");} {put("password", "password");} {put("role", "USER");} }; list.add(map); map = new HashMap<String, String>(){ private static final long serialVersionUID = 1L; {put("username", "hogehoge");} {put("password", "password2");} {put("role", "USER");} }; list.add(map); for(Map map1 : list) { if (map1.get("username").equals(username) && map1.get("password").equals(password)){ user = new User(); user.setUsername(map1.get("username").toString()); user.setPassword(map1.get("password").toString()); user.setRole(map1.get("role").toString()); break; } } return user; } }
※独自実装対応
セキュリティ設定
WebSecurityConfig.java
package com.example.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; 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.web.util.matcher.AntPathRequestMatcher; import com.example.handler.SampleAuthenticationFailureHandler; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // 認可の設定 httpSecurity .authorizeRequests() .antMatchers("/css/**", "/img/**", "/js/**", "/login").permitAll() // /loginは認証なしでアクセス可能 .antMatchers("/admin/**").hasRole("ADMIN") // ADMINユーザーのみアクセス可能 .antMatchers("/user/**").hasRole("USER") // USERユーザーのみアクセス可能 .anyRequest() .authenticated(); // ログイン設定 httpSecurity .formLogin() .loginProcessingUrl("/login") // 認証処理用 .loginPage("/login") // ログインページ .failureHandler(new SampleAuthenticationFailureHandler()) // 認証失敗時のハンドラクラス .usernameParameter("username") // ユーザー名のパラメータ .passwordParameter("password") // パスワードのパラメータ .defaultSuccessUrl("/") // 認証成功時の遷移先 .and(); // ログアウト設定 httpSecurity .logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout**")) // ログアウト処理のパス .logoutSuccessUrl("/login"); // ログイン完了後のパス } @Configuration protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { @Autowired private AuthenticationProviderImpl authenticationProvider; @Override public void init(AuthenticationManagerBuilder auth) throws Exception { // 認証方法を設定する auth.authenticationProvider(authenticationProvider); } } }
※authenticationProviderで認証設定を行う
エンティティ
User.java
package com.example.entity; import java.util.ArrayList; import java.util.Collection; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import org.springframework.data.annotation.Transient; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @Entity @Table(name = "user") public class User implements UserDetails { /** * */ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name="username") private String username; @Column(name="password") private String password; @Column(name="role") private String role; public void setUsername(String username){ this.username = username; } public void setPassword(String password){ this.password = password; } public String getRole() { return this.role; } public void setRole(String role){ this.role = role; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO Auto-generated method stub Collection<GrantedAuthority> authorityList = new ArrayList<>(); authorityList.add(new SimpleGrantedAuthority("ROLE_" + this.role)); return authorityList; } @Override public String getPassword() { // TODO Auto-generated method stub return this.password; } @Override public String getUsername() { // TODO Auto-generated method stub return this.username; } @Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { // TODO Auto-generated method stub return true; } }
※user情報設定用にsetterを付与
所感
これでなんとかDB以外のアクセスも対応できそう。
つかうかどうかはまだ不明ですがね…