[JAVA] Essayez d'utiliser Spring Boot Security

environnement

Spring Boot 1.5.9.RELEASE Java 8 Maven 4.0.0

Aperçu

Utilisez Spring Security pour vérifier et vous authentifier avec les informations de connexion dans la base de données. DB utilise H2DB et ORM utilise Doma.

introduction

Générez un projet avec Spring Inirializr. spring-initializr.png

Puisque nous utiliserons Doma pour ORM cette fois, définissez le traitement des annotations. 注釈処理.png ファクトリー・パス.png

code

Seuls ceux qui ont été modifiés par rapport à la valeur par défaut sont répertoriés.

pom.xml(※Extrait)


	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.seasar.doma.boot/doma-spring-boot-starter -->
		<dependency>
			<groupId>org.seasar.doma.boot</groupId>
			<artifactId>doma-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
	</dependencies>

UserEntity.java


package com.example.springbootsecuritysample.entity;

import java.util.Collection;

import org.seasar.doma.Entity;
import org.seasar.doma.Id;
import org.seasar.doma.jdbc.entity.NamingType;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import lombok.Getter;
import lombok.Setter;

/**
 *Entité dans la table USER
 * @author T.Harao
 *
 */
@Entity(naming = NamingType.SNAKE_UPPER_CASE)
@Getter
@Setter
public class UserEntity implements UserDetails {

	@Id
	private String userId;
	private String password;

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return null;
	}
	@Override
	public String getUsername() {
		return userId;
	}
	/**
	 *Renvoie le mot de passe à vérifier par UserDetailsService
	 *Si vous utilisez Lombok, si le champ contient "mot de passe"
	 *GetPassword avec @Getter()N'est pas nécessaire car il générera
	 */
	@Override
	public String getPassword() {
		return password;
	}
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}
	@Override
	public boolean isEnabled() {
		return true;
	}

}

UserDao.java


package com.example.springbootsecuritysample.dao;

import org.seasar.doma.Dao;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;

import com.example.springbootsecuritysample.entity.UserEntity;

/**
 *DAO accédant à la table USER
 * @author T.Harao
 *
 */
@Dao
@ConfigAutowireable
public interface UserDao {

	@Select
	public UserEntity selectByUserId(String userId);

}

AuthService.java


package com.example.springbootsecuritysample.service;

import org.springframework.beans.factory.annotation.Autowired;
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.springbootsecuritysample.dao.UserDao;
import com.example.springbootsecuritysample.entity.UserEntity;

/**
 *Service qui gère l'authentification
 * @author T.Harao
 *
 */
@Service
public class AuthService implements UserDetailsService {

	@Autowired
	private UserDao dao;

	/**
	 *Chargement de l'utilisateur
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		if(username == null || "".equals(username)) {
			throw new UsernameNotFoundException("L'ID utilisateur n'a pas été saisi");
		}

		UserEntity user = dao.selectByUserId(username);
		if(user == null) {
			throw new UsernameNotFoundException("L'ID utilisateur n'est pas valide.");
		}

		return user;
	}

}

IndexForm.java


package com.example.springbootsecuritysample.form;

import org.hibernate.validator.constraints.NotEmpty;

import lombok.Getter;
import lombok.Setter;

/**
 *Formulaire utilisé par IndexController
 * @author T.Harao
 *
 */
@Getter
@Setter
public class IndexForm {

	@NotEmpty
	private String userId;
	@NotEmpty
	private String password;

}

IndexController.java


package com.example.springbootsecuritysample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.example.springbootsecuritysample.form.IndexForm;

/**
 *S'identifier
 * @author T.Harao
 *
 */
@Controller
@RequestMapping({"/", "/index"})
public class IndexController {

	@ModelAttribute
	public IndexForm initForm(){
		return new IndexForm();
	}

	/**
	 *Affichage initial
	 * @param mv
	 * @return
	 */
	@RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mv) {
		mv.setViewName("index/index");
		return mv;
	}

	/**
	 *Au moment de l'erreur d'authentification
	 * @param mv
	 * @return
	 */
	@RequestMapping(value = {"/", "/index"}, method = RequestMethod.POST)
	public ModelAndView login(@ModelAttribute @Validated IndexForm form, BindingResult result, ModelAndView mv) {

		if(!result.hasErrors()) {
			mv.addObject("errorMessage", "Informations de connexion incorrectes");
		}

		mv.setViewName("index/index");
		return mv;
	}

}

MenuController.java


package com.example.springbootsecuritysample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 *menu
 * @author T.Harao
 *
 */
@Controller
@RequestMapping("/menu")
public class MenuController {

	/**
	 *Affichage initial
	 * @param mv
	 * @return
	 */
	@RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mv) {
		mv.setViewName("menu/index");
		return mv;
	}

}

FailureHandler.java


package com.example.springbootsecuritysample.config.handler;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

/**
 *Gestionnaire lorsque l'authentification échoue
 * @author T.Harao
 *
 */
@Component
public class FailureHandler implements AuthenticationFailureHandler {

	/**
	 *Lorsque l'authentification échoue
	 */
	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {

		//「/Transférer à
		RequestDispatcher dispatch = request.getRequestDispatcher("/");
		dispatch.forward(request, response);

	}

}

SuccessHandler.java


package com.example.springbootsecuritysample.config.handler;

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.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
/**
 *Gestionnaire en cas d'authentification réussie
 * @author T.Harao
 *
 */
@Component
public class SuccessHandler implements AuthenticationSuccessHandler {

	/**
	 *Lorsque l'authentification est réussie
	 */
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {

		//「/menu/Rediriger vers
		response.sendRedirect(request.getContextPath() + "/menu/");

	}

}

SecurityConfig.java


package com.example.springbootsecuritysample.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.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.password.NoOpPasswordEncoder;

import com.example.springbootsecuritysample.config.handler.FailureHandler;
import com.example.springbootsecuritysample.config.handler.SuccessHandler;
import com.example.springbootsecuritysample.service.AuthService;

/**
 *les paramètres de sécurité
 * @author T.Harao
 *
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private AuthService service;

	@Autowired
	private FailureHandler failureHandler;

	@Autowired
	private SuccessHandler successHandler;

	/**
	 *Paramètres de sécurité Web
	 */
	@Override
    public void configure(WebSecurity web) throws Exception {

		//Ressources statiques(images、css、javascript)Et l'accès à la console H2DB ignore les paramètres de sécurité
		web.ignoring().antMatchers("/css/**", "/fonts/**", "/images/**", "/js/**", "/h2-console/**");

	}

	/**
	 *Paramètres HttpSecurity
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		//Paramètres d'autorisation
		http.authorizeRequests()
			//Définissez une URL accessible sans authentification
			.antMatchers("/", "/index/**").permitAll()
			//Paramètres autres que ceux ci-dessus requis pour l'authentification
			.anyRequest().authenticated();

		//Paramètres de connexion
		http.formLogin()
			//Définissez le chemin pour le traitement de l'authentification
			.loginProcessingUrl("/index/login")
			//Définissez le chemin du formulaire de connexion
			.loginPage("/")
			.loginPage("/index/**")
			//Définissez l'URL à rediriger lorsque l'authentification est réussie
			.defaultSuccessUrl("/menu/")
			//Définissez l'URL à transférer lorsque l'authentification échoue
			.failureForwardUrl("/")
			//Définissez l'URL à transférer lorsque l'authentification a réussi
			//.successForwardUrl("/")
			//Définit la classe de gestionnaire à appeler lorsque l'authentification est réussie
			//.successHandler(successHandler)
			//Définir l'URL pour rediriger lorsque l'authentification échoue
			//.failureUrl("/menu/")
			//Définir une classe de gestionnaire à appeler en cas d'échec de l'authentification
			//.failureHandler(failureHandler)
			//Définir le nom d'utilisateur et le nom du paramètre de mot de passe
			.usernameParameter("userId").passwordParameter("password");

	}

	/**
	 *Réglage
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {

		//Définissez "NoOpPasswordEncoder" car le mot de passe est enregistré dans la base de données en texte brut.
		auth.userDetailsService(service)
			.passwordEncoder(NoOpPasswordEncoder.getInstance());

	}


}

layout.html


<!DOCTYPE html>
<html
	xmlns        = "http://www.w3.org/1999/xhtml"
	xmlns:th     = "http://www.thymeleaf.org"
	xmlns:layout = "http://www.ultraq.net.nz/thymeleaf/layout"
>
<head>
	<meta charset="UTF-8" />
	<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Test de sécurité de printemps</title>
	<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" media="all" />
	<link rel="stylesheet" type="text/css" href="/css/bootstrap-theme.min.css" th:href="@{/css/bootstrap-theme.min.css}" media="all" />

	<script type="text/javascript" src="/js/jquery-1.12.4.min.js" th:src="@{/js/jquery-1.12.4.min.js}"></script>
	<script type="text/javascript" src="/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
	<div class="contents" layout:fragment="contents"></div>
</body>
</html>

index/index.html


<!DOCTYPE html>
<html
	xmlns        = "http://www.w3.org/1999/xhtml"
	xmlns:th     = "http://www.thymeleaf.org"
	xmlns:layout = "http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorator="layout"
	>
<head>
	<title>S'identifier</title>
</head>
<body>
	<div layout:fragment="contents">
		<form class="form-horizontal" method="POST" action="/index/login/" th:action="@{/index/login}" th:object="${indexForm}">
			<div th:text="${errorMessage}?: ''" class="col-sm-offset-2 text-danger"></div>
			<div class="form-group">
				<p th:if="${#fields.hasErrors('*{userId}')}" th:errors="*{userId}" class="col-sm-offset-2 text-danger"></p>
				<label for="user-id" class="col-sm-2 control-label">Identifiant d'utilisateur</label>
				<div class="col-sm-5">
					<input type="text" class="form-control" id="user-id" th:field="*{userId}" placeholder="Identifiant d'utilisateur" />
				</div>
			</div>
			<div class="form-group">
				<p th:if="${#fields.hasErrors('*{password}')}" th:errors="*{password}" class="col-sm-offset-2 text-danger"></p>
				<label for="password" class="col-sm-2 control-label">mot de passe</label>
				<div class="col-sm-5">
					<input type="password" class="form-control" id="password" th:field="*{password}" placeholder="mot de passe" />
				</div>
			</div>
			<div class="form-group">
				<input type="submit" class="btn btn-primary col-sm-2 col-sm-offset-2" name="login" value="S'identifier" />
				<input type="reset" class="btn btn-default col-sm-2 col-sm-offset-1" name="clear" value="clair" />
			</div>
		</form>
	</div>
</body>
</html>

menu/index.html


<!DOCTYPE html>
<html
	xmlns        = "http://www.w3.org/1999/xhtml"
	xmlns:th     = "http://www.thymeleaf.org"
	xmlns:layout = "http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorator="layout"
	>
<head>
	<title>menu</title>
</head>
<body>
	<div layout:fragment="contents">
		<h2>menu</h2>
	</div>
</body>
</html>

application.yaml


#spring
spring:
  profiles:
    active: dev
  datasource:
    url: jdbc:h2:./db

#server
server:
  contextPath: /security-sample

#doma
doma:
  dialect: h2

application-dev.yaml


#spring
spring:
  h2:
    console:
      enabled: true
  thymeleaf:
    cache: false

application-production.yaml


#spring
spring:
  h2:
    console:
      enabled: false
  thymeleaf:
    cache: true

selectByUserId.sql


select
	user_id
	,password
from
	user
where
	user_id = /*userId*/''

schema.sql


--drop table if exists user;
create table if not exists user (
	user_id		varchar(30)	not null	primary key
	,password	varchar(30)	not null
);

data.sql


insert into user (user_id,password) values ('test','pass');

La structure des dossiers est la suivante. パッケージエクスプローラー.PNG

Contrôle de fonctionnement

Accédez à [http: // localhost: 8080 / security-sample /](http: // localhost: 8080 / security-sample /) et accédez à Entrez «test» comme ID utilisateur et «pass» comme mot de passe pour accéder à l'écran de menu. Écran de connexion ログイン.PNG Écran de menu メニュー.PNG

Traitement post-authentification

Le traitement lorsque l'authentification réussit ou échoue est décrit dans la partie suivante de SecurityConfig.java.

SecurityConfig.java


	/**
	 *Paramètres HttpSecurity
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		//Paramètres d'autorisation
		http.authorizeRequests()
			//Définissez une URL accessible sans authentification
			.antMatchers("/", "/index/**").permitAll()
			//Paramètres autres que ceux ci-dessus requis pour l'authentification
			.anyRequest().authenticated();

		//Paramètres de connexion
		http.formLogin()
			//Définissez le chemin pour le traitement de l'authentification
			.loginProcessingUrl("/index/login")
			//Définissez le chemin du formulaire de connexion
			.loginPage("/")
			.loginPage("/index/**")
			//Définissez l'URL à rediriger lorsque l'authentification est réussie
			.defaultSuccessUrl("/menu/")
			//Définissez l'URL à transférer lorsque l'authentification échoue
			.failureForwardUrl("/")
			//Définissez l'URL à transférer lorsque l'authentification a réussi
			//.successForwardUrl("/")
			//Définit la classe de gestionnaire à appeler lorsque l'authentification est réussie
			//.successHandler(successHandler)
			//Définir l'URL pour rediriger lorsque l'authentification échoue
			//.failureUrl("/menu/")
			//Définir une classe de gestionnaire à appeler en cas d'échec de l'authentification
			//.failureHandler(failureHandler)
			//Définir le nom d'utilisateur et le nom du paramètre de mot de passe
			.usernameParameter("userId").passwordParameter("password");

	}

J'ai commenté, mais lorsque l'authentification réussit et échoue Vous pouvez rediriger, transférer et déléguer le traitement à la classe de gestionnaire.

Le projet créé cette fois est en ici

Recommended Posts

Essayez d'utiliser Spring Boot Security
Tutoriel Spring Boot à l'aide de l'authentification Spring Security
Essayez d'utiliser Spring Boot avec VS Code
Essayez d'utiliser Spring JDBC
Partie 1: Essayez d'utiliser la connexion OAuth 2.0 prise en charge par Spring Security 5 avec Spring Boot
Essayez l'authentification LDAP avec Spring Security (Spring Boot) + OpenLDAP
Essayez Spring Boot sur Mac
Essayez d'utiliser un conteneur DI avec Laravel et Spring Boot
Essayez de travailler avec Keycloak en utilisant Spring Security SAML (Spring 5)
Essayez d'utiliser Maven
Essayez d'utiliser powermock-mockito2-2.0.2
Essayez d'utiliser GraalVM
Essayez d'utiliser jmockit 1.48
Essayez le cryptage / décryptage de la chaîne Spring Security AES256
Défi Spring Boot
Le test Spring Boot @WebMvcTest active la sécurité par défaut de Spring Security
Essayez Spring Boot 1 (Construction de l'environnement ~ Démarrage de Tomcat)
Forme de botte de printemps
Traitement asynchrone avec Spring Boot en utilisant @Async
Spring Boot Rappelez-vous
gae + botte à ressort
Obtenez une authentification BASIC avec Spring Boot + Spring Security
Hash des mots de passe avec Spring Boot + Spring Security (avec sel, avec étirement)
[FCM] Implémentation de la transmission de messages en utilisant FCM + Spring boot
Créez une application Spring Boot à l'aide d'IntelliJ IDEA
Essayez d'implémenter la fonction de connexion avec Spring Boot
Essayez d'automatiser la migration avec Spring Boot Flyway
Appliquer Twitter Bootstrap 4 à Spring Boot 2 à l'aide de Webjars
[Introduction à Spring Boot] Fonction d'authentification avec Spring Security
Créez un serveur Spring Cloud Config en toute sécurité avec Spring Boot 2.0
Essayez d'utiliser le Framework Axon
Fiche d'apprentissage SPRING BOOT 01
Botte de printemps + Heroku Postgres
Essayez d'utiliser l'API REST de JobScheduler
À propos de l'authentification Spring Security
Essayez d'utiliser la méthode java.lang.Math
Essayez d'utiliser la WhiteBox de PowerMock
Rédaction de mémo de démarrage de printemps (1)
Première botte à ressort (DI)
Fiche d'apprentissage SPRING BOOT 02
Aide-mémoire Spring Boot2
Gestion des exceptions Spring Boot
Mappage du servlet Spring Boot
Environnement de développement-développement Spring Boot-
Procédure d'apprentissage Spring Boot
Apprentissage de Spring Boot [Début]
Rédaction de mémos de démarrage de printemps (2)
Résumé du document Spring Boot 2.2
[Spring Boot] DataSourceProperties $ DataSourceBeanCreationException
Essayez d'utiliser Talend Part 1
Disponibilité de l'application Spring Boot 2.3
Tutoriels Spring Boot Sujets
Essayez d'utiliser la liste F #
Essayez d'utiliser la méthode each_with_index
Télécharger avec Spring Boot
Test des entités et référentiels JPA à l'aide de Spring Boot @DataJpaTest
[Note] Fichier de configuration lors de l'utilisation de Logback avec Spring Boot
Mémo d'utilisation de Spring Security: coopération avec Spring MVC et Boot