[JAVA] Implémentez la fonction d'authentification avec Spring Security ③

** Ceci est une continuation de Dernière fois. ** **

** * Nous allons créer de nombreux fichiers à partir d'ici. Si vous faites une erreur, il y a de fortes chances que vous ne puissiez pas revenir en arrière </ font>, c'est donc une bonne idée de copier les informations du projet jusqu'à ce point ou de les lister sur Github. ** ** Je ne l'ai pas fait et j'ai mis du temps à créer le projet plusieurs fois. SpringBoot_Di_Security_DB_13.png

5. Implémentation de la fonction d'authentification Spring Security.

・ Ceci est le plat principal. Si la mise en œuvre jusqu'à la dernière fois échoue, la gestion des erreurs sera gênante, alors implémentons-la parfaitement jusqu'à présent.

Modifier 5-1, POM.

-D'abord, réécrivez pom.xml, qui décrit les dépendances de Maven, afin d'introduire Spring Security. Nous allons également introduire javax.persistence pour utiliser la classe d'entité qui stocke les données reçues de la base de données.

pom.xml



<!-- SpringSecurity -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Extension Thymeleaf (sécurité)-->
<dependency>
	<groupId>org.thymeleaf.extras</groupId>
	<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
<!--Pour utiliser les annotations d'entité-->
<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
</dependency>
<!-- JpaRepository-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

・ ** Si vous écrivez simplement le code, il ne sera pas reflété. ** Le projet Maven doit être mis à jour.

"Faites un clic droit sur le projet" -> "Maven" -> "Mettre à jour le projet" pour mettre à jour le fichier Maven. Si le fichier sélectionné est correct, cliquez sur "OK" pour le mettre à jour.

-S'il n'y a pas d'erreur sur la console lorsque vous exécutez l'application, c'est OK.

5-2, implémentez la fonction d'authentification.

·C'est la fin. Enfin, nous créerons de nombreux fichiers. L'image de la structure du fichier est la suivante. ** Le cadre rouge est nouveau </ font>, Le cadre jaune est le fichier à éditer </ font>. ** **

SpringBoot_Di_Security_DB_13.png

-Aussi, j'ai fait une image du flux de traitement, alors veuillez vous y référer. (Je suis désolé, c'est très difficile à voir ...)

SpringBoot_Di_Security_DB_14.png

・ Mettez le code. J'ai écrit beaucoup de commentaires, mais honnêtement, il est difficile de tout comprendre et cela peut être faux. Nous espérons que vous enquêterez et approfondirez votre compréhension.

java:SpringLogin.app.config/WebSecurityConfig.java



package SpringLogin.app.config;

import org.springframework.beans.factory.annotation.Autowired;
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.crypto.bcrypt.BCryptPasswordEncoder;

import SpringLogin.app.service.UserDetailsServiceImpl;

/**
 *Classe de configuration pour l'utilisation de Spring Security
 *Définissez les paramètres pour le traitement de la connexion, les destinations d'accès aux données pour les transitions d'écran et le traitement de l'authentification
 * @author aoi
 *
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	//Instanciez la méthode de UserDetailsServiceImpl afin qu'elle puisse être utilisée.
	@Autowired
	private UserDetailsServiceImpl userDetailsService;
	
	//Étant donné que le mot de passe obtenu à partir de la base de données à comparer avec la valeur du formulaire est chiffré, il est également utilisé pour chiffrer la valeur du formulaire.
	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
		return bCryptPasswordEncoder;
	}
	
	/**
	 *Définir une demande pour ignorer les paramètres d'autorisation
	 *Ressources statiques(image,javascript,css)Exclure du processus d'autorisation
	 */
	@Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                            "/images/**",
                            "/css/**",
                            "/javascript/**"
                            );
    }
	
	/**
	 *Définir les informations d'authentification / d'autorisation
	 *Définissez la valeur de l'attribut name pour obtenir l'URL et les paramètres de la transition d'écran
	 *Remplacer la méthode de configuration de Spring Security.
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
		    .authorizeRequests()
		        .anyRequest().authenticated()
		        .and()
		    .formLogin()
		        .loginPage("/login") //Étant donné que la page de connexion ne passe pas par le contrôleur, il est nécessaire de la lier à ViewName.
		        .loginProcessingUrl("/login") //Soumettre l'URL du formulaire, le processus d'authentification est exécuté lorsqu'une demande est envoyée à cette URL
		        .usernameParameter("username") //Attribut de nom explicite du paramètre de demande
		        .passwordParameter("password")
		        .defaultSuccessUrl("/userList", true) //URL vers laquelle effectuer la transition lorsque l'authentification est réussie
		        .failureUrl("/login?error") //URL vers laquelle effectuer la transition en cas d'échec de l'authentification
		        .permitAll() //Tout utilisateur peut se connecter.
		        .and()
		    .logout()
		        .logoutUrl("/logout")
		        .logoutSuccessUrl("/login?logout")
		        .permitAll();
	}
	
	/**
	 *Méthode de réglage qui définit la source de données utilisée lors de l'authentification
	 *Ici, les informations utilisateur acquises à partir de la base de données sont définies dans userDetailsService pour être les informations de comparaison au moment de l'authentification.
	 * @param auth
	 * @throws Exception
	 *AuthenticationManagerBuilder a des fonctions d'authentification.
	 *Le userDetailsService est l'un d'entre eux pour déterminer si l'utilisateur saisi dans le formulaire est disponible.
	 * https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.html
	 */
	@Autowired
	public void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
		/*
		 *Pour en mémoire, utilisez:
		auth
		    .inMemoryAuthentication()
		        .withUser("user").password("{noop}password").roles("USER");
		*/
	}

}


java:SpringLogin.app.servise/UserDetailsServiceImpl.java



package SpringLogin.app.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import SpringLogin.app.repository.LoginUserDao;
import SpringLogin.app.entity.LoginUser;

/**
 *Classe d'implémentation du service Spring Security pour la recherche d'utilisateurs
 *DB peut être utilisé pour l'authentification en le spécifiant comme argument de DataSource
 * @author aoi
 *
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService{
	
	//Une classe qui implémente une méthode pour rechercher des informations utilisateur à partir de DB
	@Autowired
	private LoginUserDao userDao;
	
	/**
	 *Méthode d'implémentation de l'interface UserDetailsService
	 *Lorsque la base de données est recherchée par le nom d'utilisateur obtenu à partir du formulaire et qu'une correspondance est trouvée,
	 *Créer un objet UserDetails avec des informations de mot de passe et d'autorisation
	 *Faites un jugement de connexion en comparant la valeur d'entrée ci-dessus avec le mot de passe obtenu à partir de la base de données dans la classe de configuration.
	 */
	@Override
	public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

		LoginUser user = userDao.findUser(userName);
		
		if (user == null) {
			throw new UsernameNotFoundException("User" + userName + "was not found in the database");
		}
		//Liste des permissions
		//Il y a Admin, User, etc., mais comme nous ne les utiliserons pas cette fois, seul USER est temporairement défini.
		//Pour utiliser les autorisations, il est nécessaire de créer et de gérer des tables d'autorisations et des tables d'autorisations utilisateur sur la base de données.
		
		List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>();
		GrantedAuthority authority = new SimpleGrantedAuthority("USER");

		grantList.add(authority);
		
		//Le mot de passe RawData ne peut pas être transmis, donc le chiffrement
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        //Puisque UserDetails est une interface, transtypez l'objet utilisateur créé par le constructeur de la classe User.
		UserDetails userDetails = (UserDetails)new User(user.getUserName(), encoder.encode(user.getPassword()),grantList);
		
		return userDetails;
	}

}


java:SpringLogin.app.repository/LoginUserDao.java



package SpringLogin.app.repository;

import javax.persistence.EntityManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import SpringLogin.app.entity.LoginUser;

/**
 *Dao appelant la méthode d'accès à DB
 * @author aoi
 *
 */
@Repository
public class LoginUserDao {
	
	/**
	 *Un objet qui gère une entité.
	 *Objet requis pour convertir en la classe d'entité LoginUser avec la méthode suivante et renvoyer la valeur de retour.
	 */
	@Autowired
	EntityManager em;
	
	/**
	 *Rechercher l'utilisateur correspondant à partir de la valeur d'entrée du formulaire Null est renvoyé s'il n'y a pas de correspondance
	 * @param userName
	 * @return Quand il y a un utilisateur correspondant:UserEntity, lorsqu'elle n'existe pas:Null
	 */
	public LoginUser findUser(String userName) {

		String query = "";
		query += "SELECT * ";
		query += "FROM user ";
		query += "WHERE user_name = :userName "; //Utilisez NamedParameter pour pouvoir attribuer la valeur de l'argument avec setParameter
		
		//Étant donné que le résultat obtenu par EntityManager est un objet, il est nécessaire de le convertir en type LoginUser.
		return (LoginUser)em.createNativeQuery(query, LoginUser.class).setParameter("userName", userName).getSingleResult();
	}

}


java:SpringLogin.app.entity/LoginUser.java



package SpringLogin.app.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 *Entité pour stocker le nom d'utilisateur et le mot de passe de l'utilisateur connecté
 * @author aoi
 *
 */
@Entity
@Table(name = "user")
public class LoginUser {
	
	@Column(name = "user_id")
	@Id
	private Long userId;
	
	@Column(name = "user_name")
	private String userName;
	
	@Column(name = "password")
	private String password;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}


java:SpringLogin.app.repository/UserRepository.java



package SpringLogin.app.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import SpringLogin.app.entity.LoginUser;

/*
 *Un mécanisme de recherche de données dans Spring Framework.
 *La recherche de données devient possible en s'inscrivant dans DI. L'argument est <classe d'entité,Devenir un type d'identification>
 * https://www.tuyano.com/index3?id=12626003
 */
@Repository
public interface UserRepository extends JpaRepository<LoginUser, Integer>{

}


java:SpringLogin.app.config/SpringLoginApplication.java



package SpringLogin.app.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication //Indique qu'il s'agit d'une application Spring Boot
@ComponentScan("SpringLogin.app") //Enregistrez-vous avec DI en tant que bean. Peut être spécifié sous forme de package.
@EntityScan("SpringLogin.app.entity") //Enregistré dans DI en tant que bean comme ci-dessus.
@EnableJpaRepositories("SpringLogin.app.repository") //Pour activer le référentiel Jpa. Rechercher dans le package spécifié et@Enregistrez la classe avec Repository en tant que bean.
public class SpringLoginApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringLoginApplication.class, args);
	}

}

· Vive le bon travail. C'est un code long, mais c'est un pas de plus! Maintenant que vous avez écrit le code jusqu'à présent, vérifions-le dans votre navigateur.

5-3, contrôle de fonctionnement.

Premier accès ici → http: // localhost: 8080 / Ensuite, l'URL passera à l'écran / login. Cela prouve que Spring Security a été appliqué et, dans la méthode authorizeRequests de WebSecurityConfig.java, spécifiez une URL accessible même si vous n'êtes pas connecté. Cependant, comme rien n'est spécifié cette fois, vous ne pouvez accéder à la page de connexion que si vous n'êtes pas connecté. Ainsi, lorsque vous accédez à localhost: 8080 /, vous serez redirigé vers / login.

SpringBoot_Di_Security_DB_15.gif

・ C'est OK si cela fonctionne comme l'image ci-dessus.

-Ensuite, vérifiez la fonction d'authentification.

Connectez-vous d'abord avec le mauvais chemin et l'utilisateur. Ensuite, je ne peux pas me connecter et je suis redirigé vers "/ login? Erreur". Ceci est affecté par failureUrl () dans WebSecurityConfig.jav.

SpringBoot_Di_Security_DB_16.gif

・ C'est OK si cela fonctionne comme l'image ci-dessus.

Ensuite, connectez-vous avec un utilisateur légitime et passez. Cette fois, deux utilisateurs (user1, pass1 +) (yama, kawa) ont été créés, mais l'un ou l'autre est OK.

SpringBoot_Di_Security_DB_17.gif

・ C'est OK si cela fonctionne comme l'image ci-dessus.

Résumé

C'est tout. Merci pour votre longue relation. J'espère que vous avez en quelque sorte compris comment utiliser la fonction d'authentification et MySQL. Je ne l'ai pas encore entièrement compris, donc si vous trouvez quelque chose de mal ou de manquant, veuillez commenter:

En guise d'impression, honnêtement, Rails est monté, alors je l'ai léché un peu. C'est parce que Rails avait un appareil, donc je n'ai pas eu de mal à implémenter la fonction de connexion. Spring Security était un ordre de grandeur plus difficile ... J'ai cherché divers articles, mais y a-t-il quelqu'un qui le comprend vraiment et le résume? Je sens ça. J'ai eu du mal à poster cette fois sans le comprendre, mais je voulais le poster au plus vite pour des personnes qui souffrent comme moi, alors je l'ai posté dans cet état! J'ai encore beaucoup à faire, donc je veux améliorer mes compétences! Merci beaucoup.

Recommended Posts