カスタムしたログインページを表示、DBのユーザでログインする

#sidebar.htmlが読み込まれていない原因
　SecurityConfig.javaのセキュリティ設定を無視(ignoring)するパスの指定する際の構文が誤っていたためsidebar.htmlが読み込まれていなかったそのためログイン後の画面が表示されない


誤り

```
	@Override
	public void configure(WebSecurity web) throws Exception{
		web.ignoring().antMatchers("css/***,*/webjars/***");
	}
```

修正

```

	@Override
	public void configure(WebSecurity web) throws Exception{
		web.ignoring().antMatchers("css/***","/webjars/***");
	}

```


#結果

***1.ログイン後の画面の確認***
　ブラウザでhttp/localhost:8080/にアクセス後表示された画面でユーザ名「user」
　パスワード「password」を入力しログイン後の画面を確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/de2f6753-0d62-bafe-6d11-596cb944130d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/3b90b1fd-3f80-72ac-8795-73cd3190f135.png)

***2.Remember Meの機能が正しく機能しているか確認


2-1ログイン画面でユーザ名とパスワード入力後「ログインしたままにする」にチェックをつけてログインする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/8dbd2bde-047e-dd0b-49ec-8f6c9e4c299d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/3b90b1fd-3f80-72ac-8795-73cd3190f135.png)

2-2　ブラウザをいったん閉じ再度http:loclahost:8080/にアクセスしログイン後の画面が表示されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/da43bb79-93ff-e881-6568-4edd323197c5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/99346d35-24cd-5c3c-8874-e2870034c17f.png)



#DBのユーザでログインする。

以下のことを実施します。
***※カスタムしたログインページを表示のプログラムを使用します。***
　・DBにユーザを登録する
　・DBのユーザでログイン

#ユーティリティの作成

・列挙型を作成

```Role.java
package com.example.demo.util;

public enum Role {
	ADMIN,USER
}
```

・クラス型を作成

　Collections.unmodifiableMap()はMAPを定数として利用が可能

```Type.java
package com.example.demo.util;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class Type {

	public static final Map<Integer,String>GENDERS;
	static {
		Map<Integer,String>genders = new LinkedHashMap<>();
		genders.put(0, "選択しない");
		genders.put(1, "男性");
		genders.put(2,"女性");
		genders.put(3, "その他");
		GENDERS = Collections.unmodifiableMap(genders);
	}
	
	
}
```

#モデルの作成

```
package com.example.demo.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity

public class SiteUser {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	
	@Size(min = 2, max = 20)
	private String username;
	@Size(min =4,max = 255)
	private String password;
	
	@NotBlank
	@Email
	private String email;
	
	private int gender;
	private boolean admin;
	private String role;
	private boolean active = true;
}
```

#H2 Databaseの設定
　application.propertiesを編集
　

```
　spring.datasource.url=jdbc:h2:./textdb
　spring.jpa.hibernate.ddl-auto=update
```

　spring.datasource.url=jdbc:h2:保存先
　　DBをローカルに保存
　Spring.jpa.hibernate.ddl-auto=update
　　@Entityのテーブルがない場合、作成する。
　　 (Spring Bootアプリケーションを終了してもテーブルは削除されない)

#リポジトリ

```
package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.model.SiteUser;


public interface SiteUserRepository extends JpaRepository<SiteUser,Long> {

	SiteUser findByUsername(String username);
	boolean existsByUsername(String username);
}
```

#サービスを作成

Spring Securityはユーザデータを扱うためにインターフェースを認証に利用する。

　@Service
　　クラスがサービスそうであることを示す。
　　UserDetailsServiceインターフェースはユーザを特定するために使用される。
　　このインターフェースには実装が必要なloadUserByUsername()というメソッドがある。


```
package com.example.demo.service;

import java.util.HashSet;
import java.util.Set;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.example.demo.model.SiteUser;
import com.example.demo.repository.SiteUserRepository;
import lombok.RequiredArgsConstructor;


@RequiredArgsConstructor
@Service

public class UserDetailsServiceImpl implements UserDetailsService{
	
	private final SiteUserRepository userRepository;
	
	@Override
	public UserDetails loadUserByUsername(String username)
		throws UsernameNotFoundException{
		SiteUser user = userRepository.findByUsername(username);
		if(user == null) {
			throw new UsernameNotFoundException(username + "not found");
		}
		return createUserDetails(user);
	}

	public User createUserDetails(SiteUser user) {
		Set<GrantedAuthority> grantedAuthories = new HashSet<>();
		grantedAuthories.add(
				new SimpleGrantedAuthority("ROLE_" + user.getRole()));
		
		return new User(user.getUsername(),user.getPassword(),grantedAuthories);
				
	}
	
	
}
```

#SecurityConfigとSecurityControllerの編集

```securityConfig
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
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.web.util.matcher.AntPathRequestMatcher;
import com.example.demo.util.Role;
import lombok.RequiredArgsConstructor;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	@Override
	public void configure(WebSecurity web) throws Exception{
		web.ignoring().antMatchers("/js/**","css/***","/webjars/***");
	}
	@Override
	protected void configure(HttpSecurity http) throws Exception{
		http.authorizeRequests().antMatchers("/login","/register").permitAll()
		.antMatchers("/admin/**").hasRole(Role.ADMIN.name())
		.anyRequest().authenticated().and()
		.formLogin().loginPage("/login").defaultSuccessUrl("/").and()
		.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).and()
		.rememberMe();
	}
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}
}

```

```SecurityController.java

package com.example.demo.controller;

import org.springframework.security.core.Authentication;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo.model.SiteUser;
import com.example.demo.repository.SiteUserRepository;
import com.example.demo.util.Role;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Controller
public class SecurityController {

	@GetMapping("/login")
	public String login() {
		return "login";
	}
	@GetMapping("/")
	public String showList(Authentication loginUser,Model model) {
		model.addAttribute("username",loginUser.getName());
		model.addAttribute("role",loginUser.getAuthorities());
		return"user";
	}
	
	@GetMapping("/admin/list")
	public String showAdminList(Authentication loginUser,Model model) {
		model.addAttribute("users",userRepository.findAll());
		return "user";
		
	}
	@GetMapping("/register")
	public String register(@ModelAttribute("user") SiteUser user) {
		return "register";
	}
	
	@PostMapping("/register")
	public String process(@Validated @ModelAttribute("user") SiteUser user,BindingResult reult) {
		
		if(result.hasErrors()) {
			return "register";
		}else {
			user.setRole(Role.USER.name());
		}
		userRepository.seve(user);
		return"redirect:/login?register";
	}
}

```


#pom.xml編集

　thymeleaf-extras-springsecurity5
　　ThymeleafとSpring Security の結合モジュール
　　Thymeleafで、現在のユーザ権限などを取得できる
　datatables-buttons、datatables-plugins、jszip
　　DataTablesのボタン出力、日本語化で必要なモジュール

```
<dependency>
	<groupId>org.thymeleaf.extras</groupId>
　　<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>datatables-buttons</artifactId>
	<version>1.6.1</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>datatables-plugins</artifactId>
	<version>1.10.20</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jszip</artifactId>
	<version>3.1.0</version>
</dependency>
```



#thymeleafテンプレートを作成

 ***login.htmlを編集***

```
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<th:block th:insert="fragments/base :: header"></th:block>
</head>
<body class="bg-gradient-primary">
	<div class="container">
	<div class="row justify-content-center">
		<div class="col-xl-10 col-lg-12 col-md-9">
		<div class="card o-hidden border-0 shadow-lg my-5">
		<div class="card-body p-0">
		<div class="row">
		<div class="col-lg-6 d-none d-lg-block bg-login-image"></div>
		<div class="col-lg-6">
		<div class="p-5">
		<div class="text-center">
			<h1 class="h4 text-gray-900 mb-4">ユーザ管理システム</h1>
		</div>
		<div class="alert alert-danger" th:if="${param.error}">
			<small>ユーザ名またはパスワードが正しくありません。</small>
		</div>
		<div class="alert alert-success" th:if="${param.register}">
			<small>ユーザを新規登録しました</small>
		</div>
		<div class="alert alert-success" th:if="${param.logout}">
			<small>ログアウトしました</small>
		</div>
		<form th:action="@{/login}" class="user" method="post">
			<div class="form-group">
				<input type="text"class="form-control form-control-user" name="username"placeholder="ユーザ名">
			</div>
			<div class="form-group">
				<input type="password" class="form-control form-control-user" name="password" placeholder="パスワード">
			</div>
			<div class="form-group">
				<div class="custom-control custom-checkbox small">
				<input type="checkbox" class="custom-control-input"id="remember-me"name="remember-me">
				<label class="custom-control-label"for="remember-me">ログインしたままにする</label>
				</div>
			</div>
			<button class="btn btn-primary btn-user btn-block">ログイン</button>
			<div class="text-center">
				<a th:href="@{/register}">新規登録はこちら</a>
			</div>
		</form>
		<hr>
		</div>
		</div>
		</div>
		</div>
		</div>
		</div>
	</div>
	</div>
	<th:block th:insert="fragments/base :: scripts"></th:block>
</body>
</html>
```


#以上