[JAVA] Fonction de connexion avec Spring Security

Tous les articles ont été brièvement présentés, mais lorsque j'ai déplacé mes mains, il y avait beaucoup de choses que j'ai faites de manière inattendue. .. .. J'ai pensé que ce serait utile pour les débutants du printemps comme moi. Je vous serais reconnaissant de bien vouloir le signaler.

La voie du traitement des connexions

Qu'est-ce que Spring Security -L'authentification DB, l'authentification LDAP, l'authentification CAS, l'authentification JAAS, l'authentification X509 et l'authentification de base sont prises en charge comme méthodes d'authentification fournies par Security. Cette fois, l'authentification DB est effectuée.

■ Résultats attendus スクリーンショット 2019-03-20 19.52.28.jpg

スクリーンショット 2019-03-20 19.52.34.jpg

Choses à faire

・ 1. Ajout du contenu de build.gradle ・ 2. Paramètres d'authentification dans Security Config ・ 3. Implémentation de l'interface UserDetailsService (acquisition des informations d'authentification (créer un royaume)) ・ 4. Créer une classe LoginUser ・ 5. Création du contrôleur ・ 6. Création de HTML

Il y a six étapes principales. J'ai posté la démo sur [github] plus tôt, veuillez donc vous y référer si vous le souhaitez. ■■■ Informations de connexion ■■■ Destination de la demande: http: // localhost: 8080 / loginForm email:[email protected] password:password ■■■■■■■■■■■■■ *** Je me suis référé à l'exemple de projet d'utilisation approfondie de la suprématie sur site Spring Boot2 **.

■ Informations environnementales jdk:11 Base de données: postgresql (docker donc aucune installation requise) ┗ À propos du docker de cette démo [here] IDE:IntelliJ Système de construction: gradle

Expliquons le code source.

1. Ajouter du contenu build.gradle

build.gradle




plugins {
	id 'org.springframework.boot' version '2.1.3.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'mysql:mysql-connector-java'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	compile "org.springframework.boot:spring-boot-starter-validation"
	runtimeOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor "org.seasar.doma.boot:doma-spring-boot-starter:1.1.1"
	
	compile("org.seasar.doma.boot:doma-spring-boot-starter:1.1.1") {
		exclude group: "org.springframework.boot"
	}
	compile 'org.apache.commons:commons-lang3'
	//spring security
	compile 'org.springframework.boot:spring-boot-starter-security'
	// thymeleaf(rouleau/Contrôle des modèles Thymeleaf par permissions)
	compile "org.thymeleaf.extras:thymeleaf-extras-springsecurity5"
	compile "org.modelmapper:modelmapper:0.7.5"

}
apply plugin: 'idea'
idea.module.inheritOutputDirs = true
processResources.destinationDir = compileJava.destinationDir
compileJava.dependsOn processResources


Seules les parties liées à la sécurité des ressorts sont commentées. Ceci est juste un ajout.

2. Paramètres d'authentification dans Security Config

SecurityConfig.java



package com.example.demo;

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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.sql.DataSource;
import static com.example.demo.common.WebConst.*;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    @Autowired
    UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /**
     *Ne pas authentifier les fichiers statiques
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/favicon.ico", "/css/**", "/js/**", "/images/**", "/fonts/**", "/shutdown" /* for Demo */);
    }

    /**
     *Paramètres qui utilisent un domaine d'authentification unique qui implémente l'interface UserDetailsService
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/loginFrom").permitAll()//Formulaire de connexion autorisé
                .antMatchers("/user/**").permitAll()
                .antMatchers("/new").permitAll()//Pour le test(Enregistrement de l'utilisateur)* Effacer lorsque vous avez terminé
                .antMatchers("/index").permitAll()//Pour le test(Écran de transition après l'enregistrement de l'utilisateur) * Effacer une fois terminé
                .antMatchers("/user/create").permitAll()//Fonction pour le test * Effacer une fois terminé
                .anyRequest().authenticated();//L'accès n'est pas autorisé dans tous les autres cas sans authentification
        http.formLogin()
                .loginProcessingUrl("/login")//URL pour se connecter
                .loginPage("/loginFrom")//URL de l'écran de connexion
                .failureUrl("/login?error")//URL lorsque l'authentification échoue
                .successForwardUrl("/success")//URL lorsque l'authentification est réussie
                .usernameParameter("email")//Nom du paramètre utilisateur
                .passwordParameter("password");//Nom du paramètre de mot de passe
        http.logout()
                .logoutUrl("/logout**")//URL à la déconnexion (non implémentée cette fois)
                .logoutSuccessUrl("/login");//URL lorsque la déconnexion est réussie
    }


}


@ Configuration indique qu'il s'agit d'une classe de configuration (car elle définit un bean? Ambigu ici) -Importer la classe de configuration fournie par Spring Security avec @ EnableWebSecurity -La définition Bean de PasswordEncoder. -Il hérite de WebSecurityConfigurerAdapter et remplace la méthode configure (). Dans celui-ci, définissez l '** URL du processus d'authentification ** et définissez les paramètres. -Lorsque vous envoyez une demande à ** l'URL de traitement d'authentification **, le traitement est passé à la classe interne appelée AuthenticationConfiguration et il semble que le traitement d'authentification réel est effectué. (Extrait de la classe AuthenticationConfiguration ci-dessous)

AuthenticationConfiguration.java



@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
...réduction...
@Override
		public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
			T userDetailsService) throws Exception {
			return super.userDetailsService(userDetailsService)
				.passwordEncoder(this.defaultPasswordEncoder);
		}

...

3. Implémentation de l'interface UserDetailsService (acquisition des informations d'authentification (création de domaine))

Qu'est-ce qu'un royaume?

Le concept de royaume Selon ce

Dans le système Web, la plage à laquelle la même politique d'authentification est appliquée est appelée un domaine, et le nom qui identifie chaque domaine est appelé un nom de domaine.

Puisqu'il y a une description, je pense qu'il suffit de reconnaître le traitement pour chaque utilisateur (non limité à) pour passer pour l'authentification.

Pour décrire brièvement ce que fait le royaume créé cette fois-ci en japonais, ** [Rechercher dans la base de données en utilisant le nom d'utilisateur comme clé, renvoyer les informations de l'utilisateur s'il existe et lever une exception s'il n'existe pas. ] ** est.

UserDaoRealm.java



package com.example.demo.security;

import com.example.demo.common.security.BaseRealm;
import com.example.demo.domain.dao.UserDao;
import com.example.demo.domain.dao.UserRoleDao;
import com.example.demo.domain.dto.User;
import com.example.demo.domain.dto.UserRole;
import lombok.extern.slf4j.Slf4j;
import org.seasar.doma.jdbc.NoResultException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

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

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

@Component
@Slf4j
public class UserDaoRealm extends BaseRealm {

    @Autowired
    UserDao userDao;

    @Autowired
    UserRoleDao userRoleDao;

    @Override
    protected UserDetails getLoginUser(String email) {
        User user = null;

        List<GrantedAuthority> authorityList = null;

        try{
            user = new User();
            user.setEmail(email);

            //Obtenir un utilisateur et enregistrer dans la session
            user = userDao.select(user)
                    .orElseThrow(() -> new UsernameNotFoundException("no user found. [id=]" + email + "]"));

            //Obtenir l'autorité de contact
            List<UserRole> userRoles = userRoleDao.selectByUserId(user.getId(), toList());

            //Mettez un préfixe sur la clé de rôle et assemblez-le
            Set<String> roleKeys = userRoles.stream().map(UserRole::getRole_key).collect(toSet());

            //Récupérer les clés d'autorisation
            Set<String> permissionKeys = userRoles.stream().map(UserRole::getPermissionKey).collect(toSet());

            //Transmettez les rôles et les autorisations en tant qu'autorité accordée
            Set<String> authorities = new HashSet<>();
            authorities.addAll(roleKeys);
            authorities.addAll(permissionKeys);
            authorityList = AuthorityUtils.createAuthorityList(authorities.toArray(new String[0]));
        }catch (Exception e){
            //Ne rien faire si aucune exception n'est levée
            //Sinon, enveloppez-le dans une exception d'erreur d'authentification
            if(!(e instanceof NoResultException)){
                throw new UsernameNotFoundException("could not select user,", e);
            }
        }
        return new LoginUser(user, authorityList);
    }
}


-La classe abstraite BaseRealm est créée en implémentant ʻUserDetailsService. Il hérite de BaseRealm et crée ʻUserDaoRealm. -Doma est utilisé pour le processus d'acquisition d'informations de userDao. Pour plus d'informations, [ici] -Implémenter LoginUser avec NO.4.

・ 4. Créer une classe LoginUser

LoginUser.java



package com.example.demo.security;


import com.example.demo.domain.dto.User;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;


@Data
public class LoginUser extends org.springframework.security.core.userdetails.User {
    /**
     *constructeur
     *
     * @param user
     * @param authorities
     */
    public LoginUser(User user, Collection<? extends GrantedAuthority> authorities){
        super(String.valueOf(user.getEmail()), user.getPassword(), authorities);
    }

}


Il hérite simplement de ʻorg.springframework.security.core.userdetails.User` et définit le constructeur.

・ 5. Création du contrôleur

Tout ce que vous avez à faire est de mapper l'URL suivante sur le contrôleur. · Formulaire de connexion ・ Processus de connexion (pour vérifier l'entrée, puis la transmettre à la sécurité du ressort) · Connexion réussie

LoginController.java



package com.example.demo.web.controller;

import com.example.demo.common.controller.AbstractHtmlController;
import com.example.demo.common.controller.BaseController;
import com.example.demo.web.form.LoginForm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import static com.example.demo.common.WebConst.*;

@Controller
public class LoginController extends AbstractHtmlController {


    @Override
    public String getFunctionName() {
        return "A_LOGIN";
    }

    @ModelAttribute
    LoginForm loginForm(){return new LoginForm();}
    /**
     *Affichage de l'écran de connexion
     * @Afficher l'écran de connexion lors de l'utilisation de la méthode return get
     */
    @GetMapping("/loginForm")
    public String loginFrom(){
        return "login/login";
    }

    /**
     *Vérifiez l'entrée
     *
     * @param form
     * @param br
     * @return
     */
    @PostMapping("/login")
    public String index(@Validated @ModelAttribute LoginForm form, BindingResult br) {
        //S'il y a une erreur de vérification d'entrée, revenez à l'écran d'origine
        if (br.hasErrors()) {
            return "login/login";
        }
        //20190309 Si la vérification d'entrée réussit, transférez au processus d'authentification défini dans Security Config
        //20190309 Doit être la méthode Post, vous devez donc utiliser forward
        return "forward:" + LOGIN_PROCESSING_URL;
    }

    /**
     *Connexion réussie
     */
    @PostMapping("/success")
    public String loginsuccess(@ModelAttribute LoginForm loginForm, Model model,RedirectAttributes redirectAttributes){
        model.addAttribute("msg","loginSuccess");
        return "/login/success";
    }


}


6. Création de HTML

login.html



<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Springboot</title>
    <meta charset="utf-8" />
</head>
<body>
<h1 th:text="S'identifier"></h1>
<div th:if="${param.error}" class="alert alert-danger">
Le pseudo ou mot de passe est incorect.
</div>
<form th:action="@{'/login'}" action="../user/index.html" th:object = "${loginForm}" method="post">
    <div class="form-group" th:classappend="${#fields.hasErrors('email')}? 'has-error'">
        <label for="email" class="control-label">email</label>
        <input id="email" type="text" class="form-control" th:field="*{email}" name="email">
        <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="error-massages">error!</span>
    </div>
    <div class="form-group" th:classappend="${#fields.hasErrors('password')}? 'has-error'">
        <label for="password" class="control-label">password</label>
        <input id="password" type="password" class="form-control" th:field="*{password}" name="password">
        <span th:if="${#fields.hasErrors('password')}" th:errors="*{password}" class="error-massages">error!</span>
    </div>
    <input type="submit" class="btn btn-default" value="S'identifier"/>
</form>
</body>
</html>

À th: if =" $ {param.error} ", le paramètre d'erreur est reçu et une chaîne de caractères est sortie. Lorsque le bouton de connexion est pressé avec th: action =" @ {'/ login'} ", le processus de connexion est passé à la sécurité du printemps.

À la fin

Cette fois, je me suis concentré sur la connexion de sécurité importante et printanière. La prochaine fois, j'aimerais essayer ** de changer l'écran à afficher en fonction de l'autorité **. Merci de votre attention.

Recommended Posts

Fonction de connexion avec Spring Security
Mise en œuvre de la fonction d'authentification avec Spring Security ②
Implémentez la fonction d'authentification avec Spring Security ③
Implémentation de la fonction de connexion par Spring Security (securityConfig)
Essayez d'implémenter la fonction de connexion avec Spring Boot
[Introduction à Spring Boot] Fonction d'authentification avec Spring Security
Connexion SNS avec Spring Boot
Fonction de connexion
Créez une fonction de connexion / déconnexion avec Spring Security selon le guide officiel de Spring [pour les débutants]
Certification / autorisation avec Spring Security & Thymeleaf
Connectez-vous avec HttpServletRequest # login dans Spring Security dans l'environnement Servlet 3.x
J'ai essayé d'implémenter un client OAuth avec Spring Boot / Security (connexion LINE)
Authentification DB avec Spring Security et hachage avec BCrypt
Partie 1: Essayez d'utiliser la connexion OAuth 2.0 prise en charge par Spring Security 5 avec Spring Boot
Essayez d'implémenter une fonction de connexion avec Spring-Boot
Créez quand même une fonction de connexion avec Rails
Avec Spring Boot, hachez le mot de passe et utilisez l'enregistrement des membres et la sécurité Spring pour implémenter la fonction de connexion.
Utiliser les balises JSP Spring Security avec FreeMarker
Implémenter la fonction de pagination avec Spring Boot + Thymeleaf
Comment Spring Security fonctionne avec Hello World
Obtenez une authentification BASIC avec Spring Boot + Spring Security
Hash des mots de passe avec Spring Boot + Spring Security (avec sel, avec étirement)
Essayez l'authentification LDAP avec Spring Security (Spring Boot) + OpenLDAP
Ajoutez vos propres éléments d'authentification avec Spring Security
Créez un serveur Spring Cloud Config en toute sécurité avec Spring Boot 2.0
À propos de l'authentification Spring Security
Ressort avec actionneur Kotorin --5
Validation personnalisée avec Spring
Avec Kotorin ―― 7. Fonction de cadrage
Printemps avec Kotorin ―― 1. INITIALISATION PRINTEMPS
Fonction sans serveur avec Micronaut
Télécharger avec Spring Boot
Ressort avec Kotorin ―― 3. Omettre les crochets d'onde de la fonction
Mémo d'utilisation de Spring Security: coopération avec Spring MVC et Boot
Spring Boot avec les paramètres du filtre de sécurité Spring et les points addictifs
Implémentez une API Rest simple avec Spring Security avec Spring Boot 2.0
Gérer le mot de passe haché avec BCryptPasswordEncoder de Spring Security en Perl
Créez un site de démonstration simple avec Spring Security avec Spring Boot 2.1
Essayez de travailler avec Keycloak en utilisant Spring Security SAML (Spring 5)
Appelez votre propre méthode avec PreAuthorize dans Spring Security
Hello World avec Spring Boot
Configuration Java avec Spring MVC
Implémenter GraphQL avec Spring Boot
Mémo d'utilisation de Spring Security CSRF
Spring with Kotorin --- 8. Couche de référentiel
Démarrez avec Spring Boot
Bonjour tout le monde avec Spring Boot!
Spring avec Kotorin --6 Traitement asynchrone
Exécutez LIFF avec Spring Boot
Un nouvel employé a tenté de créer une fonction d'authentification / autorisation à partir de zéro avec Spring Security
Spring Security Usage Memo Method Security
Mémo d'utilisation de Spring Security Remember-Me
Téléchargement de fichiers avec Spring Boot
Spring Boot commençant par copie
Ressort avec Kotorin ―― 7. Couche de service
[Ruby on Rails] Implémenter la fonction de connexion par add_token_to_users avec l'API
Utilisation de Mapper avec Java (Spring)
Spring Boot à partir de Docker
[Spring Security] Spring Security sur GAE (SE)