[JAVA] Anmeldefunktion mit Spring Security

Alle Artikel wurden kurz vorgestellt, aber als ich tatsächlich meine Hände bewegte, gab es viele Dinge, die ich unerwartet tat. .. .. Ich dachte, es wäre hilfreich für Frühlingsanfänger wie mich. Ich wäre Ihnen dankbar, wenn Sie darauf hinweisen könnten.

Der Weg zur Login-Verarbeitung

Was ist Frühlingssicherheit? -DB-Authentifizierung, LDAP-Authentifizierung, CAS-Authentifizierung, JAAS-Authentifizierung, X509-Authentifizierung und Standardauthentifizierung werden als von Security bereitgestellte Authentifizierungsmethoden unterstützt. Dieses Mal wird die DB-Authentifizierung durchgeführt.

■ Erwartete Ergebnisse スクリーンショット 2019-03-20 19.52.28.jpg

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

Dinge die zu tun sind

・ 1. Hinzufügen von build.gradle-Inhalten ・ 2. Authentifizierungseinstellungen in der Sicherheitskonfiguration ・ 3. Implementierung der UserDetailsService-Schnittstelle (Erfassung von Authentifizierungsinformationen (Realm erstellen)) ・ 4. Erstellen Sie die LoginUser-Klasse ・ 5. Erstellung des Controllers ・ 6. HTML erstellen

Es gibt sechs Hauptschritte. Ich habe die Demo früher auf [github] gepostet. Wenn Sie möchten, lesen Sie sie bitte. ■■■ Anmeldeinformationen ■■■ Ziel anfordern: http: // localhost: 8080 / loginForm email:[email protected] password:password ■■■■■■■■■■■■■ *** Ich bezog mich auf das Beispielprojekt von "Site Supreme Principle Spring Boot2 Thorough Utilization **".

■ Umweltinformationen jdk:11 Datenbank: postgresql (Docker, daher keine Installation erforderlich) ┗ Über den Docker dieser Demo [hier] IDE:IntelliJ Build-System: Gradle

Lassen Sie uns den Quellcode erklären.

1. Fügen Sie den Inhalt von build.gradle hinzu

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(rollen/Steuern von Thymeleaf-Vorlagen durch Berechtigungen)
	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


Es werden nur die Teile kommentiert, die sich auf die Federsicherheit beziehen. Dies ist nur eine Ergänzung.

2. Authentifizierungseinstellungen in der Sicherheitskonfiguration

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();
    }


    /**
     *Authentifizieren Sie keine statischen Dateien
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/favicon.ico", "/css/**", "/js/**", "/images/**", "/fonts/**", "/shutdown" /* for Demo */);
    }

    /**
     *Einstellungen, die einen eindeutigen Authentifizierungsbereich verwenden, der die UserDetailsService-Schnittstelle implementiert
     * @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()//Anmeldeformular erlaubt
                .antMatchers("/user/**").permitAll()
                .antMatchers("/new").permitAll()//Zum Test(Benutzer Registration)* Löschen, wenn Sie fertig sind
                .antMatchers("/index").permitAll()//Zum Test(Übergangsbildschirm nach Benutzerregistrierung) * Löschen, wenn fertig
                .antMatchers("/user/create").permitAll()//Funktion für Test * Löschen, wenn Sie fertig sind
                .anyRequest().authenticated();//In allen anderen Fällen ist der Zugriff ohne Authentifizierung nicht zulässig
        http.formLogin()
                .loginProcessingUrl("/login")//URL zum Anmelden
                .loginPage("/loginFrom")//URL des Anmeldebildschirms
                .failureUrl("/login?error")//URL, wenn die Authentifizierung fehlschlägt
                .successForwardUrl("/success")//URL bei erfolgreicher Authentifizierung
                .usernameParameter("email")//Benutzerparametername
                .passwordParameter("password");//Name des Passwortparameters
        http.logout()
                .logoutUrl("/logout**")//URL beim Abmelden (diesmal nicht implementiert)
                .logoutSuccessUrl("/login");//URL, wenn die Abmeldung erfolgreich ist
    }


}


AuthenticationConfiguration.java



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

...

3. Implementierung der UserDetailsService-Schnittstelle (Erfassung von Authentifizierungsinformationen (Realm erstellen))

Was ist ein Reich?

Das Konzept des Reiches Demzufolge

Im Websystem wird der Bereich, auf den dieselbe Authentifizierungsrichtlinie angewendet wird, als Realm bezeichnet, und der Name, der jeden Realm identifiziert, wird als Realmname bezeichnet.

Da es eine Beschreibung gibt, denke ich, dass es ausreicht, die Verarbeitung für jeden Benutzer (nicht beschränkt auf) zu erkennen, um die Authentifizierung zu bestehen.

Um kurz zu beschreiben, was der diesmal erstellte Bereich auf Japanisch tut, ** [Durchsuchen Sie die Datenbank mit dem Benutzernamen als Schlüssel, geben Sie die Informationen des Benutzers zurück, falls vorhanden, und lösen Sie eine Ausnahme aus, wenn sie nicht vorhanden ist. ] ** ** ist.

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);

            //Benutzer abrufen und in Sitzung speichern
            user = userDao.select(user)
                    .orElseThrow(() -> new UsernameNotFoundException("no user found. [id=]" + email + "]"));

            //Kontaktbehörde einholen
            List<UserRole> userRoles = userRoleDao.selectByUserId(user.getId(), toList());

            //Setzen Sie dem Rollenschlüssel ein Präfix und setzen Sie es zusammen
            Set<String> roleKeys = userRoles.stream().map(UserRole::getRole_key).collect(toSet());

            //Sammeln Sie Autorisierungsschlüssel
            Set<String> permissionKeys = userRoles.stream().map(UserRole::getPermissionKey).collect(toSet());

            //Übergeben Sie sowohl Rollen als auch Berechtigungen als erteilte Berechtigung
            Set<String> authorities = new HashSet<>();
            authorities.addAll(roleKeys);
            authorities.addAll(permissionKeys);
            authorityList = AuthorityUtils.createAuthorityList(authorities.toArray(new String[0]));
        }catch (Exception e){
            //Tun Sie nichts, wenn 0 Ausnahmen ausgelöst werden
            //Andernfalls schließen Sie es in eine Authentifizierungsfehlerausnahme ein
            if(!(e instanceof NoResultException)){
                throw new UsernameNotFoundException("could not select user,", e);
            }
        }
        return new LoginUser(user, authorityList);
    }
}


-Die abstrakte Klasse "BaseRealm" wird durch Implementierung von "UserDetailsService" erstellt. Es erbt von "BaseRealm" und erstellt "UserDaoRealm". -Doma wird zum Erfassen von Informationen von userDao verwendet. Für Details [hier] -Implementieren Sie LoginUser mit NO.4.

・ 4. Erstellen Sie die LoginUser-Klasse

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 {
    /**
     *Konstrukteur
     *
     * @param user
     * @param authorities
     */
    public LoginUser(User user, Collection<? extends GrantedAuthority> authorities){
        super(String.valueOf(user.getEmail()), user.getPassword(), authorities);
    }

}


Es erbt nur von org.springframework.security.core.userdetails.User und definiert den Konstruktor.

・ 5. Erstellung des Controllers

Sie müssen lediglich die folgende URL auf dem Controller zuordnen. · Login Formular ・ Anmeldevorgang (um die Eingabe zu überprüfen und dann an die Federsicherheit weiterzuleiten) · Erfolgreicher Login

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();}
    /**
     *Anzeige des Anmeldebildschirms
     * @Zeigen Sie den Anmeldebildschirm an, wenn Sie die Methode return get verwenden
     */
    @GetMapping("/loginForm")
    public String loginFrom(){
        return "login/login";
    }

    /**
     *Überprüfen Sie die Eingabe
     *
     * @param form
     * @param br
     * @return
     */
    @PostMapping("/login")
    public String index(@Validated @ModelAttribute LoginForm form, BindingResult br) {
        //Wenn ein Fehler bei der Eingabeprüfung auftritt, kehren Sie zum ursprünglichen Bildschirm zurück
        if (br.hasErrors()) {
            return "login/login";
        }
        //20190309 Wenn die Eingabeprüfung erfolgreich ist, leiten Sie den in der Sicherheitskonfiguration festgelegten Authentifizierungsprozess weiter
        //20190309 Muss die Post-Methode sein, daher müssen Sie Forward verwenden
        return "forward:" + LOGIN_PROCESSING_URL;
    }

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


}


6. HTML erstellen

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="Einloggen"></h1>
<div th:if="${param.error}" class="alert alert-danger">
Der Benutzername oder das Passwort ist falsch.
</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="Einloggen"/>
</form>
</body>
</html>

Bei th: if =" $ {param.error} " wird der Fehlerparameter empfangen und eine Zeichenfolge ausgegeben. Wenn die Anmeldeschaltfläche mit "th: action =" @ {'/ login'} "gedrückt wird, wird der Anmeldevorgang an spring security übergeben.

Am Ende

Dieses Mal konzentrierte ich mich auf wichtige und frühlingshafte Sicherheitsanmeldungen. Das nächste Mal möchte ich versuchen, ** den anzuzeigenden Bildschirm je nach Behörde zu wechseln **. Danke fürs Zuhören.

Recommended Posts

Anmeldefunktion mit Spring Security
Implementierte Authentifizierungsfunktion mit Spring Security ②
Implementierte Authentifizierungsfunktion mit Spring Security ③
Implementierung der Anmeldefunktion durch Spring Security (securityConfig)
Versuchen Sie, die Anmeldefunktion mit Spring Boot zu implementieren
[Einführung in Spring Boot] Authentifizierungsfunktion mit Spring Security
SNS-Login mit Spring Boot
Anmeldefunktion
Erstellen Sie mit Spring Security eine Anmelde- / Abmeldefunktion gemäß dem offiziellen Spring-Leitfaden [für Anfänger].
Zertifizierung / Autorisierung mit Spring Security & Thymeleaf
Melden Sie sich mit HttpServletRequest # in Spring Security in der Servlet 3.x-Umgebung an
Ich habe versucht, einen OAuth-Client mit Spring Boot / Security (LINE-Anmeldung) zu implementieren.
DB-Authentifizierung mit Spring Security und Hashing mit BCrypt
Teil 1: Versuchen Sie, die von Spring Security 5 unterstützte OAuth 2.0-Anmeldung mit Spring Boot zu verwenden
Versuchen Sie, eine Anmeldefunktion mit Spring-Boot zu implementieren
Erstellen Sie trotzdem eine Anmeldefunktion mit Rails
Hash beim Spring-Boot das Passwort und verwenden Sie die Mitgliederregistrierung und die Spring-Sicherheit, um die Anmeldefunktion zu implementieren.
Verwenden Sie Spring Security JSP-Tags mit FreeMarker
Implementieren Sie die Paging-Funktion mit Spring Boot + Thymeleaf
Wie Spring Security mit Hello World funktioniert
Erreichen Sie die BASIC-Authentifizierung mit Spring Boot + Spring Security
Hash-Passwörter mit Spring Boot + Spring Security (mit Salt, mit Stretching)
Versuchen Sie die LDAP-Authentifizierung mit Spring Security (Spring Boot) + OpenLDAP
Fügen Sie mit Spring Security Ihre eigenen Authentifizierungselemente hinzu
Erstellen Sie mit Spring Boot 2.0 einen Spring Cloud Config Server mit Sicherheit
Informationen zur Spring Security-Authentifizierung
Feder mit Kotorin --5 Aktuator
Selbstgemachte Validierung mit Spring
Mit Kotorin ―― 7. Scoping-Funktion
Frühling mit Kotorin ―― 1. SPRING INITIALIZR
Serverlose Funktion mit Micronaut
Mit Spring Boot herunterladen
Feder mit Kotorin ―― 3. Auslassen von Wellenklammern aus der Funktion
Verwendungshinweis zu Spring Security: Zusammenarbeit mit Spring MVC und Boot
Spring Boot mit Spring Security Filter-Einstellungen und Suchtpunkten
Implementieren Sie eine einfache Rest-API mit Spring Security mit Spring Boot 2.0
Behandeln Sie das gehashte Passwort mit BCryptPasswordEncoder von Spring Security in Perl
Erstellen Sie mit Spring Security 2.1 eine einfache Demo-Site mit Spring Security
Versuchen Sie, mit Keycloak mit Spring Security SAML (Spring 5) zu arbeiten.
Rufen Sie Ihre eigene Methode mit PreAuthorize in Spring Security auf
Hallo Welt mit Spring Boot
Java-Konfiguration mit Spring MVC
Implementieren Sie GraphQL mit Spring Boot
Spring Security-Nutzungsnotiz CSRF
Frühling mit Kotorin --- 8. Aufbewahrungsschicht
Beginnen Sie mit Spring Boot
Hallo Welt mit Spring Boot!
Feder mit Kotorin --6 Asynchrone Verarbeitung
Führen Sie LIFF mit Spring Boot aus
Neuer Mitarbeiter hat versucht, mit Spring Security eine Authentifizierungs- / Autorisierungsfunktion von Grund auf neu zu erstellen
Sicherheit der Verwendungsnotizmethode für Spring Security
Spring Security-Nutzungsnotiz Remember-Me
Datei-Upload mit Spring Boot
Spring Boot beginnt mit dem Kopieren
Feder mit Kotorin ―― 7. Serviceschicht
[Ruby on Rails] Implementieren Sie die Anmeldefunktion von add_token_to_users mit API
Verwenden von Mapper mit Java (Spring)
Spring Boot beginnend mit Docker
[Frühlingssicherheit] Frühlingssicherheit auf GAE (SE)