Einführung in die Implementierung der Benutzerauthentifizierung mithilfe der Spring-Sicherheit. Nachdem Sie eingeführt haben, wie Sie das Passwort hashen und sich als neues Mitglied registrieren, Wir zeigen Ihnen, wie Sie Benutzer mithilfe der Spring-Sicherheit authentifizieren.
Dieses Mal haben wir den Vorgang in der folgenden Umgebung bestätigt.
DB
Erstellen Sie zunächst eine Tabelle, in der Sie Ihren Benutzernamen und Ihr Kennwort speichern können. Dieses Mal erstellen wir eine USER-Tabelle mit dem Benutzernamen (NAME), dem Kennwort (PASSWORD) und der ID als Spalten. Führen Sie die folgende SQL-Anweisung aus, um die USER-Tabelle zu erstellen.
CREATE TABLE USER(ID INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(64) NOT NULL, PASSWORD VARCHAR(64) NOT NULL);
Hier ist es wichtig, die Anzahl der Zeichen in PASSWORD auf 60 oder mehr zu setzen. Das Kennwort wird gehasht und in der Datenbank registriert. Wenn das Kennwort jedoch mit dem in diesem Hashing verwendeten BCryptPasswordEncoder gehasht wird, beträgt die Anzahl der Zeichen 60 Zeichen, sodass diesmal mindestens 60 Zeichen für die Kennwortspalte erforderlich sind.
Fügen Sie zunächst Spring-Sicherheitsabhängigkeiten ein, um die Spring-Sicherheit zu verwenden. Fügen Sie Pom.xml die folgende Abhängigkeit hinzu.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Wenn Sie eine Spring-Sicherheitsabhängigkeit einfügen, wird beim Starten der Anwendung der Standard-Anmeldebildschirm für Spring-Sicherheit angezeigt. Zu diesem Zeitpunkt wird der folgende Standard-Anmeldebildschirm angezeigt.
Lassen Sie uns nun den Anmeldebildschirm anzeigen, den Sie im nächsten Abschnitt erstellt haben.
Erstellen Sie hier einen Anmeldebildschirm, erstellen Sie einen Controller und erstellen Sie WebSecurityConfig.java.
Erstellen Sie zunächst einen Anmeldebildschirm.
Login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Einloggen</title>
</head>
<body>
<form th:action="/" method="POST">
<table align="center">
<tr>
<td>
Nutzername:
</td>
<td>
<input type="text" id="user" name="user"/>
</td>
</tr>
<tr>
<td>
Passwort:
</td>
<td>
<input type="password" id="password" name="password"/>
</td>
</tr>
<tr>
<td>
</td>
<td align="right">
<button type="submit">Einloggen</button>
</td>
</tr>
<tr>
<td>
</td>
<td align="right">
<a href="/RegistrationForm">Anmelden</a>
</td>
</tr>
</table>
</form>
</body>
</html>
Erstellen Sie als Nächstes einen Controller.
LoginController.java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
@RequestMapping("/login")
public String showLoginForm(Model model) {
//Übergang zum Anmeldebildschirm.
return "Login";
}
}
Als nächstes konfigurieren Sie mit Java-Konfiguration. Erstellen Sie eine WebSecurityConfig-Klasse für die Konfiguration. Diese Klasse erbt von WebSecurityConfigurerAdapter.
WebSecurityConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//Geben Sie die Anmeldeseite an.
//Der gesamte Zugriff auf die Anmeldeseite ist zulässig.
http.formLogin()
.loginPage("/login")
.permitAll();
http.authorizeRequests()
.anyRequest().authenticated();
}
}
Geben Sie in loginPage () den in RequestMapping der showLoginForm () -Methode der LoginController-Klasse angegebenen Pfad an. Durch Aufrufen von allowAll () können Sie auf die Anmeldeseite zugreifen, auch wenn Sie nicht authentifiziert sind. Rufen Sie anyRequest (). Authenticated () auf, um alle Anforderungen zu authentifizieren.
Wenn Sie diesen Schritt abgeschlossen haben, wird der von Ihnen erstellte Anmeldebildschirm wie unten gezeigt angezeigt.
Als nächstes werden wir die Mitgliedschaftsregistrierungsfunktion implementieren.
In diesem Kapitel wird beschrieben, wie Sie das Kennwort hashen und in der Datenbank registrieren. Das Erstellen eines Registrierungsformulars für die Mitgliedschaft und das Empfangen des Eingabewerts des Formulars sind jedoch dieselben wie wenn das Kennwort nicht gehasht wird. Daher werde ich es weglassen. Dieser Abschnitt befasst sich mit dem Hash von Passwörtern. Wenn Sie den gesamten Quellcode anzeigen möchten, finden Sie den Quellcode unter github.
Dieses Mal wird BCryptPasswordEncoder als Hashing-Methode verwendet. Hier ist die PassswordEncoder-Klasse in zwei Paketen enthalten, org.springframework.security.crypto.password und org.springframework.security.authentiction.encoding. Letzteres ist jedoch veraltet, sodass erstere Ich werde den einen benutzen. Fügen Sie zunächst BCryptPasswordEncoder mit Java-Konfiguration zur Bean hinzu.
WebSecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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 org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//Geben Sie die Anmeldeseite an.
//Der gesamte Zugriff auf die Anmeldeseite ist zulässig.
http.formLogin()
.loginPage("/login")
.permitAll();
http.authorizeRequests()
.anyRequest().authenticated();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Dieses Mal werden die Mitgliedsinformationen in die Datenbank eingefügt, indem das Kennwort und der Benutzername im Argument der Methode insertMemberInfo () der erstellten Mapper-Schnittstelle festgelegt und aufgerufen werden. Hash das im Formular eingegebene Passwort, bevor die Methode insertMemberInfo () aufgerufen wird.
RegisterMemberService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.webapp.certificationtest.mapper.RegisterMemberMapper;
@Service
@Transactional
public class RegisterMemberService {
@Autowired
RegisterMemberMapper registerMemberMapper;
@Autowired
PasswordEncoder passwordEncoder;
/**
*Registrieren Sie Mitgliedsinformationen in der DB.
*/
public void registerMember(MemberRegistrationEntity entity) {
//Hash das Passwort und insertMemberInfo()Auf das Objekt setzen, an das übergeben werden soll.
entity.setPassword(passwordEncoder.encode(entity.getPassword()));
registMemberMapper.insertMemberInfo(entity);
}
}
Hier deklarieren wir zuerst PasswordEncoder mit @ </ span> Autowired. Fügen Sie dann nach dem Aufruf von encode () von PasswordEncoder zum Hashing des Kennworts das Kennwort in die Datenbank ein.
Fügen Sie es zunächst zu WebSecurityConfig.java hinzu.
WebSecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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 org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//Geben Sie die Anmeldeseite an.
//Der gesamte Zugriff auf die Anmeldeseite ist zulässig.
http.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.usernameParameter("userName")
.passwordParameter("password")
.defaultSuccessUrl("/")
.permitAll();
//Wird hinzugefügt, wenn die Mitgliederregistrierungsfunktion implementiert ist
http.authorizeRequests()
.antMatchers("/RegistrationForm").permitAll()
.antMatchers("/Register").permitAll()
.antMatchers("/Result").permitAll()
.anyRequest().authenticated();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Geben Sie die URL an, die mit loginProcessingUrl () zum Authentifizierungsprozess verschoben werden soll. Stellen Sie sicher, dass diese URL mit dem Wert des Aktionsattributs des Formular-Tags des Anmeldeformulars übereinstimmt. Geben Sie in usernameParameter () den Wert des Namensattributs des Eingabe-Tags an, das den Benutzernamen in HTML einfügt. Geben Sie in passwordParameter () den Wert des Namensattributs des Eingabe-Tags an, mit dem das Kennwort in HTML abgelegt wird. Gibt die URL der Seite an, zu der gewechselt werden soll, wenn die Anmeldung mit defaultSuccessUrl () erfolgreich war.
Ändern Sie als Nächstes die Aktion und den Eingabenamen des Formulars in Login.html.
Login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Einloggen</title>
</head>
<body>
<form th:action="/authenticate" method="POST">
<table align="center">
<tr>
<td>
Nutzername:
</td>
<td>
<input type="text" id="user" name="userName"/>
</td>
</tr>
<tr>
<td>
Passwort:
</td>
<td>
<input type="password" id="password" name="password"/>
</td>
</tr>
<tr>
<td>
</td>
<td align="right">
<button type="submit">Einloggen</button>
</td>
</tr>
<tr>
<td>
</td>
<td align="right">
<a href="/RegistrationForm">Anmelden</a>
</td>
</tr>
</table>
</form>
</body>
</html>
Erstellen Sie als Nächstes eine Klasse, um den aus der USER-Tabelle erhaltenen Benutzernamen und das Kennwort einzugeben.
Account.java
/**
*Eine Klasse, in der die für die Anmeldung erforderlichen Mitgliedsinformationen gespeichert werden.
*/
public class Account {
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Schreiben Sie als Nächstes einen Mapper, der den Benutzernamen und das Kennwort aus der USER-Tabelle abruft.
LoginMapper.java
import com.webapp.certificationtest.Account;
public interface LoginMapper {
public Account findAccount(String name);
}
LoginMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.webapp.certificationtest.mapper.LoginMapper">
<select id="findAccount" resultType="com.webapp.certificationtest.Account"
parameterType="String">
SELECT
NAME,
PASSWORD
FROM
USER
WHERE
NAME = #{userName}
</select>
</mapper>
Erstellen Sie als Nächstes eine Klasse zum Speichern von Benutzerinformationen. Es erbt von der User-Klasse.
DbUserDetails.java
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
public class DbUserDetails extends User {
//Nutzerinformation.
private final Account account;
public DbUserDetails(Account account,
Collection<GrantedAuthority> authorities) {
super(account.getName(), account.getPassword(),
true, true, true, true, authorities);
this.account = account;
}
public Account getAccount() {
return account;
}
}
Das zweite Argument des Klassenkonstruktors DbUserDetails enthält eine Liste der Berechtigungen, die dem Benutzer erteilt werden sollen.
Erstellen Sie als Nächstes die Serviceklasse. Diese Service-Klasse ruft den Wert aus der User-Tabelle ab und generiert UserDetails. Die Authentifizierung erfolgt durch Abgleich der vom Benutzer im Anmeldeformular eingegebenen Informationen mit den hier generierten Benutzerdetails.
DbUserDetailsService.java
import java.util.Collection;
import java.util.Optional;
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.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.webapp.certificationtest.mapper.LoginMapper;
@Service
public class DbUserDetailsService implements UserDetailsService {
@Autowired
LoginMapper loginMapper;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String mailAddress)
throws UsernameNotFoundException {
//Benutzerinformationen von DB abrufen.
Account account = Optional.ofNullable(loginMapper.findOne(mailAddress))
.orElseThrow(() -> new UsernameNotFoundException("User not found."));
return new DbUserDetails(account, getAuthorities(account));
}
/**
*Legen Sie den Berechtigungsbereich fest, der diesem Benutzer bei erfolgreicher Authentifizierung erteilt wird.
* @param account Benutzerinformationen von DB erhalten.
* @return Eine Liste von Berechtigungsbereichen.
*/
private Collection<GrantedAuthority> getAuthorities(Account account) {
//Legen Sie den Berechtigungsbereich fest, der dem Benutzer bei erfolgreicher Authentifizierung erteilt wird.
return AuthorityUtils.createAuthorityList("ROLE_USER");
}
}
Wenn nichts aus der Benutzertabelle abgerufen werden kann, werfen Sie einen UsernameNotFoundExceptionw. Geben Sie im Argument UsernameNotFoundException die Nachricht an, wenn der Benutzername in der Benutzertabelle nicht vorhanden ist. Legen Sie in getAuthorities () die Berechtigungen fest, die dem Benutzer aus der Benutzertabelle erteilt wurden. Ändern Sie diese Methode nach Bedarf. Wenn Sie mehrere Berechtigungen erteilen möchten, fügen Sie diese dem durch Kommas getrennten Argument createAuthorityList () hinzu.
Fügen Sie als Nächstes zur Authentifizierung WebSecurityConfig.java hinzu.
WebSecurityConfig.java
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.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;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
//Geben Sie die Anmeldeseite an.
//Der gesamte Zugriff auf die Anmeldeseite ist zulässig.
http.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.usernameParameter("userName")
.passwordParameter("password")
.defaultSuccessUrl("/")
.permitAll();
http.csrf().disable().authorizeRequests()
.antMatchers("/RegistrationForm").permitAll()
.antMatchers("/Register").permitAll()
.antMatchers("/Result").permitAll()
.anyRequest().authenticated();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
void configureAuthenticationManager(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
}
Fügen Sie es schließlich zu LoginController.java hinzu.
LoginController.java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
/**
*Übergabe an das Anmeldeformular.
*/
@RequestMapping("/login")
public String showLoginForm(Model model) {
//Übergang zum Anmeldebildschirm.
return "Login";
}
/**
*Gehen Sie zur Hauptseite.
*Wenn die Anmeldung erfolgreich ist, wird diese Methode aufgerufen.
*/
@RequestMapping("/")
public String login(Model model) {
//Hauptseite.
return "index";
}
}
Erstellen Sie einen Bildschirm, der nach der Anmeldung angezeigt wird.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hauptseite</title>
</head>
<body>
Dies ist die Hauptseite.
</body>
</html>
Überprüfen Sie den Betrieb.
Erstens ist die Registrierung der Mitgliedschaft.
Geben Sie Ihren Benutzernamen und Ihr Passwort ein, um sich zu registrieren.
Wenn die Registrierung der Mitgliedschaft abgeschlossen ist, wird das Passwort gehasht und auf diese Weise in die Datenbank eingefügt.
Als nächstes folgt die Anmeldung.
Geben Sie den Benutzernamen und das Passwort ein, die Sie zuvor registriert haben.
Ich konnte mich einloggen und zur Hauptseite wechseln.
Der Quellcode bis zu diesem Punkt ist unter github aufgeführt. Wenn Sie also alle anzeigen möchten, lesen Sie dies bitte. Wenn Sie Fragen haben, kontaktieren Sie mich bitte auf Twitter.