#はじめに
SQLServer接続編で作成したプロジェクトを拡張していきます。
順番にコピペしていけば、とりあえず動く物は出来上がります。
コピペ中にエラーが発生しない順番にこだわりました。
ですので、このタイミングでこのコードが存在しているの?必要か?と言う部分もあります。
エラーチェック処理は不完全です。あらかじめご了承下さい。
下記の仕様で作成しました。
- SQLServer接続編で作成したプロジェクトを拡張する。
- 独自のユーザーテーブルを作成して認証を行う。
- ロールによる動作の違いを見られるように、管理ユーザーと一般ユーザー2つを作成する。
- 一般ユーザーを登録出来るのは管理ユーザーのみとする。
- 管理ユーザーは一つしか作成出来ない。
- CSS、JavaScriptは使用しない。
#環境
OS:Windows 10 Pro 64bit
DB:SQL Server 2019(Cent OS 8 on Hyper-V)
Editor:Visual Studio Code 1.44.2
JDK:AdoptOpenJDK 11.0.6+10 x64
Apache Maven:v3.6.3
Apache Tomcat:v9.0.31
#作成手順
1.ユーザー情報を保存するテーブルの作成
2.DBアクセスに必要なentity、repositoryの作成
3.Spring Securityを使用する為の設定
4.管理ユーザー登録ページの作成
5.一般ユーザー登録ページの作成
#ユーザー情報を保存するテーブルの作成
こちらで作成したDBにユーザー情報を保存するUserInfoテーブルと、ロールを保存するUserRolesテーブルを作成します。
CREATE TABLE [dbo].[UserInfo](
[UserId] [varchar](255) NOT NULL,
[Password] [varchar](255) NOT NULL,
[UserNameJP] [nvarchar](255) NOT NULL,
[SectionNameJP] [nvarchar](255) NOT NULL,
[Enabled] [bit] NOT NULL,
CONSTRAINT [PK_UserInfo] PRIMARY KEY CLUSTERED
(
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY];
CREATE TABLE [dbo].[UserRoles](
[UserId] [varchar](255) NOT NULL,
[Authority] [varchar](255) NOT NULL,
CONSTRAINT [PK_UserRoles] PRIMARY KEY CLUSTERED
(
[UserId] ASC,
[Authority] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY];
#プロジェクト作成
SQLServer接続編で作成したプロジェクトを「D:\JAVA\Project\securitySample」にコピーして作成しました。
###pom.xml
Spring Securityに必要なRepositoryと、パスワードの文字数チェックに使用するRepositoryを追加します。
<properties>
<spring-security.version>5.3.0.RELEASE</spring-security.version>
</properties>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
<scope>compile</scope>
</dependency>
pom.xml全体です。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>securitySample1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
<spring.version>5.2.4.RELEASE</spring.version>
<spring-security.version>5.3.0.RELEASE</spring-security.version>
<!-- web.xmlが無い場合でもビルドを実行する -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.2.1.jre11</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.2.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
##entity作成
ユーザー情報を格納するentityを作成します。
- UserInfo.java
- UserRoles.java
D:\JAVA\Project\securitySample\src\main\java\com\example\persistence
└─entity
├─UserInfo.java
└─UserRoles.java
###UserRoles.java
ロール(権限)を格納します。
package com.example.persistence.entity;
import lombok.Data;
@Data
public class UserRoles {
private String userId;
private String authority;
public UserRoles() {}
public UserRoles(String userId, String authority) {
this.userId = userId;
this.authority = authority;
}
}
###UserInfo.java
ユーザー情報を格納します。
package com.example.persistence.entity;
import java.util.List;
import lombok.Data;
@Data
public class UserInfo {
private String userId;
private String password;
private String userNameJP;
private String sectionNameJP;
private Boolean enabled;
private List<UserRoles> userRolesList;
public UserInfo() {}
public UserInfo(String userId, String userNameJP, String sectionNameJP, Boolean enabled) {
this.userId = userId;
this.userNameJP = userNameJP;
this.sectionNameJP = sectionNameJP;
this.enabled = enabled;
}
}
##repositoryの作成
DBへアクセスするrepositoryを作成します。
- UserInfoRepository.java
- UserInfoRepositoryImpl.java
- UserRolesRepository.java
- UserRolesRepositoryImpl.java
D:\JAVA\Project\securitySample\src\main\java\com\example\persistence
└─repository
├─UserInfoRepository.java
├─UserInfoRepositoryImpl.java
├─UserRolesRepository.java
└─UserRolesRepositoryImpl.java
###UserInfoRepository.java
package com.example.persistence.repository;
import java.util.List;
import java.util.Optional;
import com.example.persistence.entity.UserInfo;
public interface UserInfoRepository {
Optional<UserInfo> selectDetailByUserId(String id);
Integer insert(UserInfo userInfo);
Integer update(UserInfo userInfo);
Integer delete(String userId);
List<UserInfo> findUserAll();
}
###UserInfoRepositoryImpl.java
package com.example.persistence.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.persistence.entity.UserInfo;
import com.example.persistence.entity.UserRoles;
@Repository
public class UserInfoRepositoryImpl implements UserInfoRepository{
@Autowired
NamedParameterJdbcTemplate jdbcTemplate;
private static final RowMapper<UserInfo> INFO_MAPPER = (rs, rowNum) ->
new UserInfo(rs.getString("UserId"),
rs.getString("UserNameJP"),
rs.getString("SectionNameJP"),
rs.getBoolean("Enabled")
);
private static final RowMapper<UserRoles> ROLES_MAPPER = (rs, rowNum) ->
new UserRoles(rs.getString("UserId"),
rs.getString("Authority")
);
@Override
public Optional<UserInfo> selectDetailByUserId(String id) {
try {
UserInfo userInfo = new UserInfo();
List<UserRoles> userRolesList = new ArrayList<UserRoles>();
String sql = "SELECT UserInfo.UserId, UserInfo.Password, UserInfo.UserNameJP, UserInfo.SectionNameJP, UserInfo.Enabled"
+ " , UserRoles.Authority"
+ " FROM UserInfo INNER JOIN UserRoles ON UserInfo.UserId = UserRoles.UserId "
+ " WHERE (UserInfo.UserId = :id)";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("id", id);
List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql, parameterSource);
for(Map<String, Object> result : resultList) {
UserRoles userRoles = new UserRoles();
userRoles.setUserId((String) result.get("UserId"));
userRoles.setAuthority((String) result.get("Authority"));
userRolesList.add(userRoles);
userInfo.setUserId((String) result.get("UserId"));
userInfo.setPassword((String) result.get("Password"));
userInfo.setUserNameJP((String) result.get("UserNameJP"));
userInfo.setSectionNameJP((String) result.get("SectionNameJP"));
userInfo.setEnabled((Boolean) result.get("Enabled"));
}
userInfo.setUserRolesList(userRolesList);
return Optional.of(userInfo);
}catch (EmptyResultDataAccessException e) {
return Optional.empty();
}
}
@Override
public Integer insert(UserInfo userInfo) {
String sql = "INSERT INTO UserInfo"
+ " VALUES(:UserId, :Password, :UserNameJP, :SectionNameJP, :Enabled);";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userInfo.getUserId());
parameterSource.addValue("Password", userInfo.getPassword());
parameterSource.addValue("UserNameJP", userInfo.getUserNameJP());
parameterSource.addValue("SectionNameJP", userInfo.getSectionNameJP());
parameterSource.addValue("Enabled", userInfo.getEnabled());
Integer rows = jdbcTemplate.update(sql, parameterSource);
return rows;
}
@Override
public Integer update(UserInfo userInfo) {
String sql = "UPDATE UserInfo SET "
+ " Password = :Password "
+ ",UserNameJP = :UserNameJP "
+ ",SectionNameJP = :SectionNameJP "
+ ",Enabled = :Enabled "
+ " WHERE UserId = :UserId;";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userInfo.getUserId());
parameterSource.addValue("Password", userInfo.getPassword());
parameterSource.addValue("UserNameJP", userInfo.getUserNameJP());
parameterSource.addValue("SectionNameJP", userInfo.getSectionNameJP());
parameterSource.addValue("Enabled", userInfo.getEnabled());
Integer rows = jdbcTemplate.update(sql, parameterSource);
return rows;
}
@Override
public Integer delete(String userId) {
String sql = "DELETE FROM UserInfo WHERE UserId = :UserId;";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userId);
Integer rows = jdbcTemplate.update(sql, parameterSource);
return rows;
}
@Override
public List<UserInfo> findUserAll() {
String sql1 = "SELECT DISTINCT UserInfo.UserId, UserInfo.UserNameJP, UserInfo.SectionNameJP, UserInfo.Enabled"
+ " FROM UserInfo INNER JOIN UserRoles ON UserInfo.UserId = UserRoles.UserId "
+ " WHERE UserRoles.Authority = 'ROLE_USER'"
+ " ORDER BY UserInfo.UserId;" ;
List<UserInfo> userInfoList = jdbcTemplate.query(sql1, INFO_MAPPER);
userInfoList.forEach(userInfo -> {
String sql2 = "SELECT * FROM UserRoles WHERE UserId = :UserId;";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userInfo.getUserId());
List<UserRoles> userRolesList = jdbcTemplate.query(sql2, parameterSource, ROLES_MAPPER);
userInfo.setUserRolesList(userRolesList);
});
return userInfoList;
}
}
###UserRolesRepository.java
package com.example.persistence.repository;
import com.example.persistence.entity.UserRoles;
public interface UserRolesRepository {
Integer insert(UserRoles userRoles);
Integer update(UserRoles userRoles);
Integer delete(String userId);
Integer adminCheck();
}
###UserRolesRepositoryImpl.java
package com.example.persistence.repository;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.persistence.entity.UserRoles;
@Repository
public class UserRolesRepositoryImpl implements UserRolesRepository {
@Autowired
NamedParameterJdbcTemplate jdbcTemplate;
@Override
public Integer insert(UserRoles userRoles) {
String sql = "INSERT INTO UserRoles"
+ " VALUES(:UserId, :Authority);";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userRoles.getUserId());
parameterSource.addValue("Authority", userRoles.getAuthority());
Integer rows = jdbcTemplate.update(sql, parameterSource);
return rows;
}
@Override
public Integer update(UserRoles userRoles) {
String sql = "UPDATE UserRoles SET Authority = :Authority"
+ " WHERE UserId = :UserId;";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userRoles.getUserId());
parameterSource.addValue("Authority", userRoles.getAuthority());
Integer rows = jdbcTemplate.update(sql, parameterSource);
return rows;
}
@Override
public Integer delete(String userId) {
String sql = "DELETE FROM UserRoles WHERE UserId = :UserId;";
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("UserId", userId);
Integer rows = jdbcTemplate.update(sql, parameterSource);
return rows;
}
@Override
public Integer adminCheck() {
Integer rows = 0;
String sql = "SELECT COUNT(*) AS CNT"
+ " FROM UserRoles"
+ " WHERE Authority = 'ROLE_ADMIN';" ;
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
Map<String, Object> result = jdbcTemplate.queryForMap(sql,parameterSource);
rows = Integer.parseInt(result.get("CNT").toString());
return rows;
}
}
##security部作成
「D:\JAVA\Project\sqlSample\src\main\java\com\example」に「security」フォルダを作成します。
その直下にconfigフォルダを作成します。
configフォルダに以下のファイルを作成します。
- SecurityConfig.java
- SpringSecurityInitializer.java
securityフォルダ直下には以下のファイルを作成します。
- MyAccessDeniedHandler.java
- MyAuthenticationSuccessHandler.java
- MyUserDetails.java
- MyUserDetailsService.java
D:\JAVA\Project\securitySample\src\main\java\com\example\security
├─config
| ├─SecurityConfig.java
| └─SpringSecurityInitializer.java
├─MyAccessDeniedHandler.java
├─MyAuthenticationSuccessHandler.java
├─MyUserDetails.java
└─MyUserDetailsService.java
###MyAuthenticationSuccessHandler.java
認証成功時に表示するページを指定します。
ロールごとに分ける事も可能です。
package com.example.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
//認証後のリダイレクト先
if (authentication.getAuthorities().toString().contains("ADMIN")) {
// ADMINロールはユーザー登録ページを表示する。
redirectStrategy.sendRedirect(request, response, "/userReg/index");
} else {
// それ以外のロールの時に表示するページ。
redirectStrategy.sendRedirect(request, response, "/hello/index");
}
}
}
###MyAccessDeniedHandler.java
認証処理でエラーが発生した際、表示するページを指定します。
package com.example.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.access.AccessDeniedHandler;
public class MyAccessDeniedHandler implements AccessDeniedHandler{
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.sendRedirect(request, response, "/auth/403");
}
}
###MyUserDetails.java
標準の認証情報に追加したい項目を追加します。
ユーザー名の日本語項目と部署名を追加しています。
package com.example.security;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import com.example.persistence.entity.UserInfo;
public class MyUserDetails extends User {
private static final long serialVersionUID = 1L;
private final String userNameJP;
private final String sectionNameJP;
public MyUserDetails(UserInfo userInfo, List<? extends GrantedAuthority> authorityList) {
super(userInfo.getUserId(), userInfo.getPassword(), userInfo.getEnabled(), true, true, true, authorityList);
this.userNameJP = userInfo.getUserNameJP();
this.sectionNameJP = userInfo.getSectionNameJP();
}
public String getUserNameJP() {
return userNameJP;
}
public String getSectionNameJP() {
return sectionNameJP;
}
}
###MyUserDetailsService.java
package com.example.security;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
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.example.persistence.entity.UserInfo;
import com.example.persistence.entity.UserRoles;
import com.example.persistence.repository.UserInfoRepository;
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserInfoRepository userInfoRepository;
@Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
Optional<UserInfo> userInfoOpt = userInfoRepository.selectDetailByUserId(userId);
if (userInfoOpt == null) {
throw new UsernameNotFoundException("");
}
UserInfo userInfo = userInfoOpt.get();
List<SimpleGrantedAuthority> authorityList = new ArrayList<SimpleGrantedAuthority>();
List<UserRoles> roles = userInfo.getUserRolesList();
for (UserRoles role: roles) {
authorityList.add(new SimpleGrantedAuthority(role.getAuthority()));
}
return new MyUserDetails(userInfo, authorityList);
}
}
###SecurityConfig.java
今回のアプリではBasic認証は使っておりませんが、Form認証と併用する例として、記述してあります。
Basic認証を優先する記述になっています。
package com.example.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.CharacterEncodingFilter;
import com.example.security.MyAccessDeniedHandler;
import com.example.security.MyAuthenticationSuccessHandler;
import com.example.security.MyUserDetailsService;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService());
}
@Bean
public UserDetailsService myUserDetailsService() {
return new MyUserDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* Basic認証
*/
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class WebSecurityBasicConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/admin/**").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic()
;
}
}
/**
* Form認証
*/
@Configuration
public class WebSecurityFormConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
http
.addFilterBefore(filter, CsrfFilter.class)
.authorizeRequests()
//どのロールでもアクセス可
.antMatchers("/", "/resources/**", "/webjars/**", "/auth/**", "/adminReg/**").permitAll()
// ロールにるアクセス設定
// '/userReg/'で始まるURLには、'ADMIN'ロールのみアクセス可
.antMatchers("/userReg/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.loginPage("/auth/login")
.failureUrl("/auth/login-error")
.successHandler(new MyAuthenticationSuccessHandler())
.permitAll()
.and()
// ログアウト処理の設定
.logout()
// ログアウト処理のURL
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
// ログアウト成功時の遷移先URL
.logoutSuccessUrl("/auth/login")
// ログアウト時に削除するクッキー名
.deleteCookies("JSESSIONID")
// ログアウト時のセッション破棄を有効化
.invalidateHttpSession(true)
.permitAll()
.and()
//403エラー時の遷移先設定
.exceptionHandling()
.accessDeniedHandler(new MyAccessDeniedHandler())
;
}
}
}
###SpringSecurityInitializer.java
package com.example.security.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
###WebAppInitializer.java追記
WebAppInitializerのgetRootConfigClassesにSecurityConfig.classを追加します。
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {SecurityConfig.class, PersistenceConfig.class, ServiceConfig.class};
}
WebAppInitializer.java全体です。
package com.example.web.config;
import java.nio.charset.StandardCharsets;
import javax.servlet.Filter;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.example.persistence.config.PersistenceConfig;
import com.example.security.config.SecurityConfig;
import com.example.service.config.ServiceConfig;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* ビジネスロジックなど、Spring MVC以外に関するJava Configクラスを指定します。
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {SecurityConfig.class, PersistenceConfig.class, ServiceConfig.class};
}
/**
* Spring MVCに関するJava Configクラスを指定します。
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {MvcConfig.class};
}
/**
* DispatcherServletに対するURLパターンを指定します。
* "/"を指定することで、全リクエストをDispatcherServletが受け取ります。
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* サーブレットフィルターを指定します。
* 複数のフィルターがあった場合、配列に指定した順番に実行されます。
*/
@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new CharacterEncodingFilter(StandardCharsets.UTF_8.name(), true)
};
}
}
#まとめ
以上でSpring Securityを使う上で必要な準備が終わりました。
次はログインページ、管理ユーザー作成ページを作っていきます。