Wenn Sie schnell und ohne lange Geschichte Code schreiben möchten, überspringen Sie [1. Einführung](Nr. 1 - Einführung). Für Frühlingsanfänger gehen Sie zu [2. Projekt erstellen](# 2 - Projekt erstellen). Für diejenigen, die eine einfache Authentifizierungs- / Autorisierungsfunktion implementieren möchten, siehe [3. Implementierung einer einfachen Authentifizierungs- / Autorisierungsfunktion](# 3-Implementierung einer einfachen Authentifizierungs- / Autorisierungsfunktion) Diejenigen, die die Authentifizierungs- / Autorisierungsfunktion für das tatsächliche Geschäft implementieren möchten, sollten mit dem Lesen von [4. Implementierung der Authentifizierungs- / Autorisierungsfunktion für das tatsächliche Geschäft] beginnen (# 4 - Implementierung der Authentifizierungs- / Autorisierungsfunktion für das tatsächliche Geschäft).
Zunächst werde ich die Authentifizierung / Autorisierung erläutern. Die einfache Erklärung lautet wie folgt. (Referenzseite für diejenigen, die mehr wissen möchten: Vertraute Authentifizierung und Autorisierung)
--Authentifizierung Überprüfen Sie, mit wem Sie kommunizieren </ font>.
--Genehmigung Gewähren Sie die Ressourcenzugriffsberechtigung für bestimmte Bedingungen wie Bildschirmzugriffsberechtigung und Verarbeitungsberechtigung </ font>.
Wenn Sie diese Authentifizierungs- / Autorisierungsfunktion in einer mit Spring Framework erstellten Webanwendung implementieren, kann sie mithilfe von Spring Security problemlos implementiert werden. Es gibt viele Artikel, die Authentifizierungs- / Autorisierungsfunktionen mit Spring Security implementieren, aber ich bin der Meinung, dass es viele Artikel wie die folgenden gibt.
Datenbanknutzung und Passwort-Hashing sind jedoch an der Tagesordnung </ font>. Als ich ein Websystem mit Authentifizierungs- / Autorisierungsfunktionen erstellte, hatte ich große Probleme, viele Artikel zu lesen und den Quellcode auf GitHub zu dekodieren. Basierend auf dieser Erfahrung benötigen selbst Anfänger in Bezug auf Spring Security und Authentifizierung / Autorisierung eine Datenbank sowie Hashing und Artikel, die die Funktion implementieren können, indem sie diese </ font> lesen. Ich dachte und schrieb diesen Artikel. In dem vor Ort verwendeten System fragen Sie sich außerdem, wie der Quellcode und die Datenbanktabellen für die Authentifizierung / Autorisierung implementiert sind. Daher habe ich diesen Artikel mit der Absicht geschrieben, zu untersuchen, welche Art von Authentifizierungs- / Autorisierungsfunktion implementiert ist, indem ich auf , unser Beispiel für die Systemkonstruktion </ font>, verwiesen habe.
――Sie müssen den Quellcode von GitHub nicht lesen, sondern nur diesen Artikel lesen, und selbst Anfänger können Authentifizierungs- / Autorisierungsfunktionen mit Spring Security implementieren. ――Wir fassen den Inhalt der Untersuchung und Anhörung zur Authentifizierung und Autorisierung unter Bezugnahme auf unser Beispiel für den Systemaufbau als Methode zur Implementierung der Authentifizierungs- und Autorisierungsfunktion für das tatsächliche Geschäft zusammen.
――Zwei Implementierungen, einfache Implementierung und Implementierung für das tatsächliche Geschäft.
** Einfache Implementierung ** </ font> ist eine Implementierung der Authentifizierungs- / Autorisierungsverarbeitung für Anfänger. Nur der Implementierungsteil des Spring Security-Referenzmaterials wird vom Autor zusammengefasst. Es ist perfekt für Anfänger von Spring Security, um ein besseres Verständnis zu erlangen, indem sie es auf ihrem eigenen Gerät ausführen. ** Implementierung für das eigentliche Geschäft ** </ font> basiert auf internen Anhörungen darüber, wie die Authentifizierungs- / Autorisierungsverarbeitung in einem tatsächlichen System realisiert wird. Wir werden eine Authentifizierungs- / Autorisierungsverarbeitung implementieren, die dem tatsächlichen System nahe kommt. Es ist eine Implementierung für diejenigen, die die Authentifizierungs- / Autorisierungsverarbeitung im Geschäftsleben entwickeln.
--Die in diesem Artikel vorgestellten Einstellungen / Funktionen sollten als eine der Einstellungen / Funktionen verstanden werden, die bei der Anwendung eines tatsächlichen Projekts berücksichtigt werden müssen.
Die folgenden drei Ziele gelten sowohl für die einfache Implementierung als auch für die praktische Implementierung </ font>.
1-7. GitHub Auch wenn Sie den Quellcode nicht auf GitHub lesen, können Sie die Funktion implementieren, indem Sie diesen Artikel lesen. Für diejenigen, die sagen "Es ist schneller, GitHub zu lesen", werde ich den Quellcode auf GitHub veröffentlichen.
https://github.com/YukiYamagata/SpringSecurity-Qiita
--BasicAuth ist der Quellcode der einfachen Implementierungsauthentifizierungs- / Autorisierungsfunktion.
Es ist geworden.
"Fenster" -> "Perspektive" -> "Offene Perspektive" -> "Andere"
Wählen Sie zum Öffnen "Java EE"
"Datei" -> "Neu" -> "Spring Starter Project"
Ändern Sie den Wert jedes Elements wie unten gezeigt und klicken Sie auf "Weiter".
Artikel | Wert |
---|---|
Name | Beliebiger Wert |
Schimmel | Gradle (Buildship 3.x) |
Java-Version | 11 |
Ergebnisse | Beliebiger Wert |
Drücken Sie "Fertig stellen"
Da Eigenschaften und yml nur geringfügig unterschiedlich beschrieben werden, gibt es kein Problem, auch wenn sie als "application.properties" belassen werden. Ich mag, ob ich es ändern soll. In diesem Artikel basiert der Quellcode jedoch auf application.yml.
Die folgende Abbildung zeigt ein Bild des erstellten Websystems. Der detaillierte Verarbeitungsablauf für die Authentifizierungs- und Autorisierungsverarbeitung lautet [3-5-1. Überblick über die Spring Security-Authentifizierungsfunktion](# 3-5-1-spring-security-Überblick über die Authentifizierungsfunktion) und [3-6-1. Spring Übersicht über die Sicherheitsautorisierungsfunktion](# 3-6-1-spring-Sicherheitsübersicht über die Autorisierungsfunktion).
Die folgende Abbildung zeigt die Projektstruktur des Systems.
Schreiben Sie build.gradle, um die Abhängigkeiten festzulegen.
build.gradle
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
runtimeOnly 'com.h2database:h2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
H2DB ist eine in Java geschriebene In-Memory-Datenbank. Die Merkmale von H2DB sind die folgenden drei.
Da es sich um eine In-Memory-Datenbank handelt, gehen die Daten nach Abschluss des Vorgangs verloren. Es kann auch als eingebettete Datenbank verwendet werden, diesmal wird es jedoch installiert, um den Inhalt der Datenbank für das tatsächliche Geschäft in [4. Implementierung der Authentifizierungs- / Autorisierungsfunktion für das tatsächliche Geschäft] zu verbessern (# 4 - Implementierung der Authentifizierungs- / Autorisierungsfunktion für das tatsächliche Geschäft). Wird als Speicherdatenbank verwendet. Da es sich im Arbeitsspeicher befindet, muss der Anfangswert von H2DB durch Ausführen einer SQL-Anweisung bei jedem Start der Verarbeitung festgelegt werden. Im Fall von Spring Boot kann die SQL-Anweisung durch Beschreiben der SQL-Anweisung in "schema.sql" und "data.sql" bei jedem Start des Prozesses automatisch ausgeführt werden. </ font>
Beschreiben der H2DB-Einstellungen in application.yml.
application.yml
##datasource
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb
username: sa
password: dm
Beschreiben der Tabellenstruktur der Datenbank in SQL.
schema.sql
CREATE TABLE IF NOT EXISTS users (
username VARCHAR(18) NOT NULL PRIMARY KEY,
password VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
rolename VARCHAR(10) NOT NULL
);
Fügen Sie Daten in H2DB ein. Die 60-stellige Zeichenfolge, die mit "\ $ 2a \ $ 10 \ $" beginnt, ist das Hash-Passwort. Details werden in [3-7. Hashing-Passwörter](# 3-7-Hashing-Passwörter) erläutert. Bitte kopieren Sie diese und fügen Sie sie hier ein.
Einfaches Passwort | Hashed Passwort |
---|---|
admin | $2a$10$bCR1jXhdqbh1oC8ckXplxePYW5Kyb/VjN28MZx2PwXf1ybzLIFUQG |
user | $2a$10$yyT1siJCep647RT/I7KjcuUB5noFVU6RBo0FUXUJX.hb2MIlWTbDe |
data.sql
INSERT INTO users(username, password, name, rolename) VALUES ('admin', '$2a$10$bCR1jXhdqbh1oC8ckXplxePYW5Kyb/VjN28MZx2PwXf1ybzLIFUQG', 'admin-name', 'ADMIN');
INSERT INTO users(username, password, name, rolename) VALUES ('user' , '$2a$10$yyT1siJCep647RT/I7KjcuUB5noFVU6RBo0FUXUJX.hb2MIlWTbDe', 'user-name' , 'USER' );
Erstellen Sie eine Anwendung, die die fünf unten gezeigten Seiten anzeigen und zu diesen wechseln kann.
Die Anwendungsverarbeitung zur Realisierung dieses Seitenübergangs ist der Teil, der in der folgenden Abbildung von hellgrün umgeben ist. Um sich auf die Authentifizierungs- / Autorisierungsverarbeitung zu konzentrieren, erstellen Sie nur Controller und View für die Anwendungsverarbeitung. (Service, Dao usw. werden nicht erstellt.)
LoginController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class LoginController {
@GetMapping("/loginForm")
String loginForm() {
return "login";
}
}
HomeController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/home")
public String home() {
return "home";
}
}
AdminPageController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AdminPageController {
@GetMapping("/adminPage")
public String adminPage() {
return "adminPage";
}
}
UserPageController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class UserPageController {
@GetMapping("/userPage")
public String userPage() {
return "userPage";
}
}
AccessDeniedPageController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AccessDeniedPageController {
@GetMapping("/accessDeniedPage")
public String accessDeniedPage() {
return "accessDeniedPage";
}
}
Erstellen Sie eine HTML-Datei. Der Quellcode verwendet Thymeleaf als Template-Engine. Wenn Sie keinen "Vorlagen" -Ordner haben, fügen Sie einen unter src / main / resources hinzu.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Einloggen</title>
</head>
<body>
<h1>Einloggen</h1>
<div th:if="${param.error}" > <!-- (1)Beurteilung der Anforderungsparameter-->
<div>
Benutzername oder Passwort ist unterschiedlich.<!-- (2)Authentifizierungsfehlermeldung-->
</div>
</div>
<form method="post" th:action="@{/authenticate}"> <!-- (3)Geben Sie den Anmeldeprozesspfad an-->
<label>UserName:</label>
<input type="text" id="userName" name="userName"> <!-- (4)Eingabe des Benutzernamens-->
<br>
<label>Password:</label>
<input type="password" id="password" name="password"> <!-- (5)Abschnitt zur Passworteingabe-->
<br>
<input type="submit" id="submit" value="Einloggen">
</form>
</body>
</html>
Artikelnummer | Erläuterung |
---|---|
(1) | Beurteilen Sie die im Anforderungsparameter festgelegte Fehlermeldung. 3-5-6. JavaConfig(Datei hinzufügen) "WebSecurityConfig.java"ImÄndern Sie den Beurteilungsprozess gemäß dem in "failUrl" festgelegten Wert.Bitte beachten Sie, dass dies erforderlich ist. |
(2) | Ausnahmemeldung, die ausgegeben werden soll, wenn ein Authentifizierungsfehler auftritt |
(3) | Geben Sie im Aktionsattribut des Formulars das Übergangsziel für die Authentifizierungsverarbeitung an. Der Übergangszielpfad ist3-5-6. JavaConfig(Datei hinzufügen) "WebSecurityConfig.java"Im"Passen Sie den in loginProcessingUrl angegebenen Wert an. ”Es gibt Bedarf. Geben Sie "POST" für die HTTP-Methode an. In diesem Fall${pageContext.request.contextPath}/Der Authentifizierungsprozess wird durch Zugriff auf die Authentifizierung ausgeführt. |
(4) | Ein Element, das im Authentifizierungsprozess als "Benutzername" behandelt wird. Das Namensattribut lautet3-5-6. JavaConfig(Datei hinzufügen) "WebSecurityConfig.java"Im"Passen Sie den in usernameParameter angegebenen Wert an. “Es gibt Bedarf. |
(5) | Ein Element, das bei der Authentifizierung als "Kennwort" behandelt wird. Das Namensattribut lautet3-5-6. JavaConfig(Datei hinzufügen) "WebSecurityConfig.java"Im"Passen Sie den von passwordParameter angegebenen Wert an. “Es gibt Bedarf. |
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>Home</h1>
<form method="get" th:action="@{/adminPage}">
<input type="submit" value="Zu AdminPage">
</form>
<form method="get" th:action="@{/userPage}">
<input type="submit" value="Zur Benutzerseite">
</form>
<form method="post" th:action="@{/logout}"> <!-- (1)Geben Sie den Abmeldeverarbeitungspfad an-->
<input type="submit" value="Ausloggen">
</form>
</body>
</html>
Artikelnummer | Erläuterung |
---|---|
(1) | Geben Sie den Pfad zum Ausführen des Abmeldevorgangs im Aktionsattribut des Formulars an. Der Abmeldeprozesspfad ist der Standardwert für Spring Security./Geben Sie die Abmeldung an. Geben Sie "POST" für die HTTP-Methode an. |
adminPage.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>AdminPage</title>
</head>
<body>
<h1>Admin Page</h1>
<table border="1">
<tr>
<th>Artikel</th>
<th>Inhalt</th>
</tr>
<tr>
<td>UserName</td>
<td><span sec:authentication="principal.username"></span></td> <!-- (1)Benutzername anzeigen-->
</tr>
<tr>
<td>Name</td>
<td><span sec:authentication="principal.name"></span></td> <!-- (2)Name anzeigen-->
</tr>
<tr>
<td>Role</td>
<td><span sec:authentication="principal.authorities"></span></td> <!-- (3)Rolle anzeigen-->
</tr>
</table>
<form method="get" th:action="@{/home}">
<input type="submit" value="Nach Hause">
</form>
<form method="post" th:action="@{/logout}">
<input type="submit" value="Ausloggen">
</form>
</body>
</html>
Artikelnummer | Erläuterung |
---|---|
(1) | Verwenden Sie Thymeleaf, um auf das Authentifizierungsobjekt zuzugreifen und den Benutzernamen anzuzeigen. |
(2) | Verwenden Sie Thymeleaf, um auf das Authentifizierungsobjekt zuzugreifen und den Namen anzuzeigen. |
(3) | Verwenden Sie Thymeleaf, um auf das Authentifizierungsobjekt zuzugreifen und die Rolle anzuzeigen. |
userPage.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>UserPage</title>
</head>
<body>
<h1>User Page</h1>
<table border="1">
<tr>
<th>Artikel</th>
<th>Inhalt</th>
</tr>
<tr>
<td>UserName</td>
<td><span sec:authentication="principal.username"></span></td>
</tr>
<tr>
<td>Name</td>
<td><span sec:authentication="principal.name"></span></td>
</tr>
<tr>
<td>Role</td>
<td><span sec:authentication="principal.authorities"></span></td>
</tr>
</table>
<form method="get" th:action="@{/home}">
<input type="submit" value="Nach Hause">
</form>
<form method="post" th:action="@{/logout}">
<input type="submit" value="Ausloggen">
</form>
</body>
</html>
accessDeniedPage.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Access Denied</title>
</head>
<body>
<h1>Zugriff verweigert</h1>
<form method="get" th:action="@{/home}">
<input type="submit" value="Nach Hause">
</form>
<form method="post" th:action="@{/logout}">
<input type="submit" value="Ausloggen">
</form>
</body>
</html>
Der in der folgenden Abbildung von Rosa umgebene Teil zeigt die Authentifizierungsfunktion.
Der Ablauf des Authentifizierungsprozesses ist wie folgt. (Die Verarbeitungsnummer entspricht der Nummer in der obigen Abbildung)
(※1) UserDetailsService Es ist eine Schnittstelle, die für den Erwerb der für den Authentifizierungsprozess und den Benutzerstatus erforderlichen Anmeldeinformationen (Benutzername und Kennwort) verantwortlich ist. (※2) UserDetails Eine Schnittstelle, die Anmeldeinformationen und Benutzerstatus bereitstellt und aus "UserDetailsService" erstellt wurde.
Erstellen Sie bei der Authentifizierungsverarbeitung mit DB die UserDetailsService-Implementierungsklasse (AccountUserDetailsService in diesem Artikel) und die UserDetails-Implementierungsklasse (AccountUserDetails in diesem Artikel) gemäß den Anforderungen der Anwendung. </ font> Muss sein.
MyUser.java
package com.example.demo.entity;
import java.io.Serializable;
public class MyUser implements Serializable{
private String userName; //In H2DB die Benutzertabelle"username"Feld zum Speichern
private String password; //In H2DB die Benutzertabelle"password"Feld zum Speichern
private String name; //In H2DB die Benutzertabelle"name"Feld zum Speichern
private String roleName; //In H2DB die Benutzertabelle"roleName"Feld zum Speichern
/**
* getter, setter
*/
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;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
Greifen Sie mit Spring JDBC auf die Datenbank zu.
UserDao.java
package com.example.demo.repository;
import com.example.demo.entity.MyUser;
public interface UserDao {
MyUser findUserByUserName(String userName);
}
UserDaoImpl.java
package com.example.demo.repository;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.MyUser;
@Repository
public class UserDaoImpl implements UserDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public UserDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
*Führen Sie die SELECT-Anweisung mit userName als Suchbedingung aus, um nach in der Datenbank registrierten Benutzern zu suchen.
* @param userName
* @return User
*/
@Override
public MyUser findUserByUserName(String userName) {
String sql = "SELECT username, password, name, rolename FROM users WHERE username = ?";
//Holen Sie sich einen Benutzer
Map<String, Object> result = jdbcTemplate.queryForMap(sql, userName);
//Entitätsklasse(Benutzertyp)Umstellung auf
MyUser user = convMapToUser(result);
return user;
}
/**
*Ergebnis der Ausführung der SQL SELECT-Anweisung(Map<String, Object>)Zum Benutzertyp
* @param Map<String, Object>
* @return User
*/
private MyUser convMapToUser(Map<String, Object> map) {
MyUser user = new MyUser();
user.setUserName((String) map.get("username"));
user.setPassword((String) map.get("password"));
user.setName((String) map.get("name"));
user.setRoleName((String) map.get("rolename"));
return user;
}
}
AccountUserDetailsService.java
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
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.demo.entity.MyUser;
import com.example.demo.repository.UserDao;
@Service
public class AccountUserDetailsService implements UserDetailsService {
private final UserDao userDao;
@Autowired
public AccountUserDetailsService(UserDao userDao) {
this.userDao = userDao;
}
@Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException { // --- (1)Methode zum Abrufen von Kontoinformationen aus der Datenbank
if (userName == null || "".equals(userName)) {
throw new UsernameNotFoundException(userName + "is not found");
}
//Eine Benutzerausnahme abrufen tritt auf, wenn kein Benutzername vorhanden ist
try {
//Benutzer abrufen
MyUser myUser = userDao.findUserByUserName(userName);
if (myUser != null) {
return new AccountUserDetails(myUser); // --- (2)Generieren Sie eine Implementierungsklasse für UserDetails
} else {
throw new UsernameNotFoundException(userName + "is not found");
}
} catch (EmptyResultDataAccessException e) {
throw new UsernameNotFoundException(userName + "is not found");
}
}
}
Artikelnummer | Erläuterung |
---|---|
(1) | Suchen Sie nach Kontoinformationen aus der Datenbank. Wirf UsernameNotFoundException, wenn keine Kontoinformationen gefunden werden |
(2) | Wenn die Kontoinformationen gefunden werden, die Implementierungsklasse von UserDetails(AccountUserDetails)Generieren. |
AccountUserDetails.java
package com.example.demo.service;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import com.example.demo.entity.MyUser;
public class AccountUserDetails implements UserDetails {
private final MyUser myUser;
public AccountUserDetails(MyUser myUser) {
this.myUser = myUser;
}
public MyUser getUser() { // --- (1)Methode zur Rückgabe von MyUser als Entität
return myUser;
}
public String getName() { // --- (2)Methode zur Rückgabe des Namens
return this.myUser.getName();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() { // --- (3)Methode zum Zurückgeben der dem Benutzer erteilten Berechtigungsliste
return AuthorityUtils.createAuthorityList("ROLE_" + this.myUser.getRoleName());
}
@Override
public String getPassword() { // --- (4)Methode zur Rückgabe des registrierten Passworts
return this.myUser.getPassword();
}
@Override
public String getUsername() { // --- (5)Methode zur Rückgabe des Benutzernamens
return this.myUser.getUserName();
}
@Override
public boolean isAccountNonExpired() { // --- (6)Methode zum Ermitteln des Ablaufstatus eines Kontos
return true;
}
@Override
public boolean isAccountNonLocked() { // --- (7)Methode zum Ermitteln des Sperrstatus eines Kontos
return true;
}
@Override
public boolean isCredentialsNonExpired() { // --- (8)Eine Methode zum Ermitteln des Ablaufstatus von Anmeldeinformationen
return true;
}
@Override
public boolean isEnabled() { // --- (9)Methode, um festzustellen, ob es sich um einen gültigen Benutzer handelt
return true;
}
}
Artikelnummer | Erläuterung |
---|---|
(1) | Eine Methode, die MyUser zurückgibt, eine Entität. Bereiten Sie eine Getter-Methode vor, damit nach erfolgreichem Authentifizierungsprozess auf die Kontoinformationen zugegriffen werden kann. |
(2) | Eine Methode, die den Namen zurückgibt. |
(3) | Eine Methode, die die dem Benutzer erteilte Berechtigungsliste zurückgibt. Diese Methode wird im Autorisierungsprozess verwendet. Im Autorisierungsprozess von Spring Security wird "ROLE_Die mit "beginnenden Berechtigungsinformationen werden als Rolle behandelt. Deshalb "ROLLE_"Hinzugefügt. |
(4) | Eine Methode zum Zurückgeben des registrierten Passworts. Das von dieser Methode zurückgegebene Kennwort wird zum Vergleich mit dem vom Client angegebenen Kennwort verwendet. |
(5) | Eine Methode, die einen Benutzernamen zurückgibt. |
(6) | Eine Methode zum Ermitteln des Ablaufstatus eines Kontos. Wenn es innerhalb des Ablaufdatums liegt, wird true zurückgegeben, und wenn es abgelaufen ist, wird false zurückgegeben. In diesem Programm wird der Einfachheit halber nur true zurückgegeben. |
(7) | Eine Methode zum Ermitteln des Sperrstatus eines Kontos. Wenn es nicht gesperrt ist, wird ture zurückgegeben, und wenn das Konto gesperrt ist, wird false zurückgegeben. In diesem Programm wird der Einfachheit halber nur true zurückgegeben. |
(8) | Eine Methode, die den Ablaufstatus von Anmeldeinformationen bestimmt. Wenn es innerhalb des Ablaufdatums liegt, wird true zurückgegeben, und wenn es abgelaufen ist, wird false zurückgegeben. In diesem Programm wird der Einfachheit halber nur true zurückgegeben. |
(9) | Eine Methode, die bestimmt, ob der Benutzer gültig ist. Wenn es gültig ist, gibt es true zurück, und wenn es ein ungültiger Benutzer ist, wird false zurückgegeben. In diesem Programm wird der Einfachheit halber nur true zurückgegeben. |
WebSecurityConfig.java
package com.example.demo.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.method.configuration.EnableGlobalMethodSecurity;
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;
import com.example.demo.service.AccountUserDetailsService;
@Configuration
@EnableWebSecurity // --- (1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AccountUserDetailsService userDetailsService;
PasswordEncoder passwordEncoder() {
//Hash-Passwörter mit dem BCrypt-Algorithmus
return new BCryptPasswordEncoder(); // --- (2)Verwenden Sie den BCrypt-Algorithmus
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//Legen Sie den implementierten UserDetailsService in AuthenticationManagerBuilder fest
auth.userDetailsService(userDetailsService) // --- (3)Legen Sie den erstellten UserDetailsService fest
.passwordEncoder(passwordEncoder()); // --- (2)Geben Sie an, wie das Kennwort gehasht werden soll(BCrypt-Algorithmus)
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//Autorisierungseinstellungen
http.authorizeRequests()
.antMatchers("/loginForm").permitAll() // --- (4) /loginForm ermöglicht den Zugriff aller Benutzer
.anyRequest().authenticated(); // --- (5) /Fragen Sie nach der Authentifizierung außer loginForm
//Login-Einstellungen
http.formLogin() // --- (6)Aktivieren Sie die Formularauthentifizierung
.loginPage("/loginForm") // --- (7)Pfad zum Anzeigen des Anmeldeformulars
.loginProcessingUrl("/authenticate") // --- (8)Pfad des Formularauthentifizierungsprozesses
.usernameParameter("userName") // --- (9)Benutzername Anfrage Parameter Name
.passwordParameter("password") // --- (10)Name des Parameters für die Kennwortanforderung
.defaultSuccessUrl("/home") // --- (11)Standardpfad für den Übergang, wenn die Authentifizierung erfolgreich ist
.failureUrl("/loginForm?error=true"); // --- (12)Pfad zum Übergang, wenn die Authentifizierung fehlschlägt
//Abmeldeeinstellungen
http.logout()
.logoutSuccessUrl("/loginForm") // --- (13)Pfad zum Übergang, wenn die Abmeldung erfolgreich ist
.permitAll(); // --- (14)Ermöglichen Sie allen Benutzern den Zugriff
}
}
Artikelnummer | Erläuterung |
---|---|
(1) | @EnableWebSecurity Wenn angegeben, wird die Bean-Definition der Komponente, die zur Verwendung von Spring Security erforderlich ist, automatisch ausgeführt. |
(2) | Verwenden Sie den BCrypt-Algorithmus, um das Kennwort-Hashing festzulegen. |
(3) | AuthenticationManagerBuilder Erstellt inUserDetailsService Einstellen. |
(4) | /loginForm ermöglicht den Zugriff aller Benutzer. |
(5) | /Anders als bei loginForm ist eine Authentifizierung erforderlich. Nicht authentifizierte Benutzer werden zum Anmeldebildschirm umgeleitet. Benutzern, die authentifiziert, aber nicht autorisiert sind, wird der Zugriff verweigert. |
(6) | formLogin Die Formularauthentifizierung wird aktiviert, wenn Sie die Methode aufrufen. |
(7) | Geben Sie den Pfad an, um das Anmeldeformular anzuzeigen. Wenn ein anonymer Benutzer versucht, auf eine Seite zuzugreifen, für die eine Authentifizierung erforderlich ist, wird er auf den hier angegebenen Pfad umgeleitet. |
(8) | Geben Sie den Pfad für die Verarbeitung der Formularauthentifizierung an.3-4-4. View(Datei hinzufügen)Einloggen.In HTMLPassen Sie das Aktionsattribut des Formular-Tags anEs gibt Bedarf. |
(9) | Geben Sie den Anforderungsparameternamen des Benutzernamens an, der der Berechtigungsnachweis ist.3-4-4. View(Datei hinzufügen)Einloggen.In HTMLPassen Sie das Namensattribut des Eingabe-Tags an, um den Benutzernamen einzugebenEs gibt Bedarf. |
(10) | Geben Sie den Namen des Anforderungsparameters des Kennworts an, das die Anmeldeinformationen enthält.3-4-4. View(Datei hinzufügen)Einloggen.In HTMLPassen Sie das Namensattribut des Eingabe-Tags an, um das Kennwort einzugebenEs gibt Bedarf. |
(11) | Geben Sie den Standardpfad für den Übergang an, wenn die Authentifizierung erfolgreich ist. |
(12) | Geben Sie den Pfad an, zu dem der Übergang erfolgen soll, wenn die Authentifizierung fehlschlägt. |
(13) | Geben Sie den Pfad an, zu dem der Übergang erfolgen soll, wenn die Abmeldung erfolgreich ist. |
(14) | Ermöglichen Sie allen Benutzern den Zugriff auf Abmeldungen und Pfade, die nach erfolgreichen Abmeldungen übergehen. |
Der in der folgenden Abbildung von Hellblau umgebene Teil zeigt die Berechtigungsfunktion.
Wenn der Zugriff gewährt wird Weiter zum nächsten Filter.
Wenn der Zugriff verweigert wird Der "Filter Security Interceptor" löst eine Ausnahme namens "AccessDeniedException" aus. "Exception Translation Filter" fängt die Ausnahme ab und wenn der Zugriff von einem nicht authentifizierten Benutzer stammt, eine Antwort, die zur Authentifizierung auffordert (Übergang zum Anmeldebildschirm), und wenn der Zugriff von einem authentifizierten Benutzer stammt, eine Antwort, die einen Autorisierungsfehler benachrichtigt (Zugriff verweigert) (Übergang zum Bildschirm) wird zurückgegeben.
Die Datei, zu der der Code hinzugefügt wird, ist blau hervorgehoben.
Wenn Sie versuchen, auf eine Seite zuzugreifen, die nicht zulässig ist, werden Sie zu einer Seite weitergeleitet, die angibt, dass der Zugriff verweigert wurde.
WebSecurityConfig.java
/*Kürzung*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //Nachtrag--- (1)Aktivieren Sie die Verarbeitung der Methodenautorisierung
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/*Kürzung*/
protected void configure(HttpSecurity http) throws Exception {
//Autorisierungseinstellungen
http.exceptionHandling() //Nachtrag
.accessDeniedPage("/accessDeniedPage") //Nachtrag--- (2)Pfad zum Übergang, wenn der Zugriff verweigert wird
.and() //Nachtrag
.authorizeRequests()
.antMatchers("/loginForm").permitAll()
.anyRequest().authenticated();
/*Kürzung*/
Artikelnummer | Erläuterung |
---|---|
(1) | @PreAuthorize Oder@PostAuthorize Aktivieren Sie den Methodenautorisierungsprozess mit. |
(2) | Zugriff verweigert(Autorisierungsfehler)Wenn dies erledigt ist, geben Sie den Pfad an, zu dem der Übergang erfolgen soll. |
Beschreiben Sie "@ PreAuthorize" in jeder Methode, um die Zugriffsberechtigung festzulegen.
AdminPageController.java
/*Kürzung*/
@GetMapping("/adminPage")
@PreAuthorize("hasRole('ROLE_ADMIN')") //Nachtrag--- (1) ROLE_Zugriff nur für ADMIN-Benutzer zulassen
public String adminPage() {
/*Kürzung*/
Artikel | Erläuterung |
---|---|
(1) | 「ROLE_Nur Benutzer mit "ADMIN" haben Zugriff. |
UserPageController.java
/*Kürzung*/
@GetMapping("/userPage")
@PreAuthorize("hasRole('ROLE_USER')") //Nachtrag--- (1) ROLE_Erlauben Sie den Zugriff nur USER-Benutzern
public String userPage() {
/*Kürzung*/
Artikel | Erläuterung |
---|---|
(1) | 「ROLE_Nur Benutzer mit "USER" haben Zugriff. |
Auf der "Homepage" werden die Schaltflächen "to adminPage" und "to userPage" entsprechend den Anmeldeinformationen angezeigt.
home.html
<!---->
<body>
<h1>Home</h1>
<div sec:authorize="hasRole('ADMIN')"> <!--(1) ROLE_-->
<form method="get" th:action="@{/adminPage}">
<input type="submit" value="">
</form>
</div>
<div sec:authorize="hasRole('USER')"> <!--(2) ROLE_-->
<form method="get" th:action="@{/userPage}">
<input type="submit" value="Addendum-Anzeige nur für ADMIN-Benutzer zu AdminPage Addendum-Anzeige nur für USER-Benutzer zu UserPage">
</form>
</div>
<div sec:authorize="isAuthenticated()"> <!--Nachtrag(3)Nur angemeldete Benutzer anzeigen-->
<form method="post" th:action="@{/logout}">
<input type="submit" value="Ausloggen">
</form>
</div>
</body>
</html>
Artikel | Erläuterung |
---|---|
(1) | 「ROLE_Es werden nur Benutzer mit "ADMIN" angezeigt. |
(2) | 「ROLE_Es werden nur Benutzer mit "USER" angezeigt. |
(3) | Du bist eingeloggt(Zertifiziert)Es wird nur der Benutzer angezeigt. |
Hashing ist die Konvertierung eines Strings in einen anderen Wert (Hash-Wert) unter Verwendung eines bestimmten Algorithmus (Hash-Funktion). Es wird häufig zum Speichern von Passwörtern verwendet. Der Unterschied zwischen Verschlüsselung und Hashing besteht darin, ob der ursprüngliche Wert wiederhergestellt (entschlüsselt) werden kann. Verschlüsselte Werte können entschlüsselt werden, aber Hash-Werte können nicht entschlüsselt werden </ font>. Daher ist es für einen Dritten äußerst schwierig, die Originaldaten aus dem Hashwert </ font> zu ermitteln. Spring Security empfiehlt die Verwendung von BCryptPasswordEncoder, es sei denn, Sie haben spezielle Anforderungen für das Hashing.
Wenn Sie mehr über Hashing erfahren möchten, lesen Sie bitte die folgende Seite. Grundkenntnisse Was ist Verschlüsselung? Was ist Hashing? Wie kann ein Passwortverlust verhindert werden? ](Https://qiita.com/bayasist/items/da4be3a90a97b8cf38fe)
Ich denke, es ist besser, das folgende Programm mit einem neu erstellten Projekt zu erstellen. (Spring Security muss im neuen Projekt noch als Abhängigkeit festgelegt werden.) Sie können ein Programm mit einem vorhandenen Projekt erstellen. Der Autor ist jedoch der Ansicht, dass es besser ist, ein neues Projekt zu erstellen, da mehrere Hauptfunktionen im selben System erstellt werden können. Ändern Sie den rawPassword-Wert (admin in Ihrem Code) in den Wert, den Sie als Kennwort festlegen möchten.
GeneratePassword.java
package com.example.demo.password;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class GeneratePassword {
public static void main(String[] args) {
//Geben Sie das Passwort ein, das Sie hashen möchten
String rawPassword = "admin";
//Hash-Passwort
String password = getEncodePassword(rawPassword);
//Hash-Wert anzeigen
System.out.println(password);
}
private static String getEncodePassword(String rawPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder ();
return passwordEncoder.encode(rawPassword);
}
}
Führen Sie das in [3-7-2. Erstellen eines Kennwort-Hashing-Programms](# 3-7-2-Erstellen eines Kennwort-Hashing-Programms) in einer Java-Anwendung erstellte Programm aus.
Der auf der Konsole angezeigte Wert ist das Hash-Passwort.
Einführung in die Implementierung der Multi-Factor-Authentifizierung (MFA). In den letzten Jahren haben viele Systeme MFA eingeführt, um die Sicherheit zu verbessern. Da MFA in vielen unserer Systeme installiert ist, möchte ich einen Artikel darüber schreiben, wie MFA als praktische Implementierung implementiert wird. Die Implementierung von MFA wird etwas langwierig sein und im folgenden Artikel ausführlich erläutert. Es ist ein Implementierungsartikel von MFA, der ein Kennwort und ein Einmalkennwort verwendet. Wird gerade erstellt (bitte etwas länger warten)
Als Ergebnis der Anhörung über das tatsächliche System im Unternehmen war eine davon "Zugriffskontrollinformationen in der Datenbank speichern und Berechtigungsverarbeitung durchführen". (In [3. Implementierung einer einfachen Authentifizierungs- / Autorisierungsfunktion](# 3 - Implementierung einer einfachen Authentifizierungs- / Autorisierungsfunktion) wurde die Autorisierungsverarbeitung unter Verwendung von Anmerkungen durchgeführt.) Ich möchte einen Artikel darüber schreiben, wie die Berechtigungsverarbeitung basierend auf den in dieser Datenbank gespeicherten Zugriffssteuerungsinformationen als Implementierung für das tatsächliche Geschäft implementiert wird.
In der einfachen Implementierung wurde die Autorisierungsfunktion mit @ PreAuthorize
implementiert. In einem tatsächlichen System scheint die Autorisierungsfunktion jedoch häufig mithilfe von DB implementiert zu werden. Der Grund dafür ist, dass die Seiten, die den Zugriff auf die Rolle </ font> ermöglichen, einfach zu verwalten sind.
Wenn "@ PreAuthorize" verwendet wird, werden für jeden Controller und jede Methode Anmerkungen hinzugefügt, sodass sie in verschiedenen Dateien verteilt werden und es schwierig wird zu wissen, welche Seite für welche Rolle zulässig ist. Dies kann sehr unklar und ineffizient sein, wenn Sie den Code später erneut lesen oder das System ändern.
Auf der anderen Seite ist es viel einfacher, Rollen und Seiten zu verwalten, die den Zugriff </ font> ermöglichen, indem Sie die folgende Tabelle in der Datenbank erstellen und Zugriffssteuerungsinformationen nur in der Datenbank verwalten > Wird.
Hier ist ein Beispiel für einen Teil der Tabelle, der dieses Mal verwendet wird. Das "*" in "Rolle" ist ein Platzhalter. Dies bedeutet, dass allen Rollen (einschließlich nicht authentifizierten Benutzern) Berechtigungen erteilt werden. Es bedeutet auch, dass "/ adminPage" die Rolle "ADMIN" und "/ userPage" die Rolle "USER" erhält.
Role | Authorize Page |
---|---|
* | /loginForm |
ADMIN | /adminPage |
USER | /userPage |
Die Seitenübergänge sind die gleichen wie in der einfachen Implementierung, wie in der folgenden Abbildung gezeigt.
Der in der folgenden Abbildung von Blau umgebene Teil zeigt den Genehmigungsprozess für das tatsächliche Geschäft. Erstellen Sie im Autorisierungsprozess Abstimmungsprozess, Service und DAO. Die Autorisierungsfunktion wird realisiert, indem die Datenbank abgefragt wird, um festzustellen, ob die Seite (URL), auf die die Clientbenutzerinformationen (Rolle) zugreifen möchten, zulässig ist.
Der Ablauf der Autorisierungsverarbeitung ist wie folgt. (Die Verarbeitungsnummer entspricht der Nummer in der obigen Abbildung)
AccessDeniedException
wird von" ExceptionTranslationFilter "abgefangen.(※1) AccessDecisionManager Eine Schnittstelle, die überprüft, ob Sie Zugriff auf die Ressource haben, auf die Sie zugreifen möchten. Es gibt drei Arten von Implementierungsklassen, die von Spring Security bereitgestellt werden. Alle rufen jedoch die Vote-Methode der Schnittstelle namens AccessDecisionVoter auf, um zu bestimmen, ob Zugriffsrechte gewährt werden sollen. "AccessDecisionVoter" stimmt für "Gewähren", "Verweigern" oder "Zurückziehen", und die Implementierungsklasse von "AccessDecisionManager" aggregiert die Abstimmungsergebnisse, um das endgültige Zugriffsrecht zu bestimmen. Wenn festgestellt wird, dass Sie keinen Zugriff haben, wird eine "AccessDeniedException" ausgelöst und der Zugriff verweigert. Die folgende Tabelle zeigt die von Spring Security bereitgestellten Implementierungsklassen.
Implementierungsklasse | Erläuterung |
---|---|
AffirmativeBased | AccessDecisionVoter Um abzustimmenGewähren Sie Zugriff, wenn ein "Zuschuss" gewählt wirdImplementierungsklasse.デフォルトで使用されるImplementierungsklasse. |
ConsensusBased | AlleAccessDecisionVoter Um abzustimmenGeben Sie Zugriff, wenn die Anzahl der "Grant" -Stimmen groß istImplementierungsklasse. |
UnanimousBased | AccessDecisionVoter Um abzustimmenKein Zugriffsrecht, wenn eine "Verweigerung" gewählt wirdImplementierungsklasse. |
(※2) AccessDecisionVoter
AccessDecisionVoter
ist eine Schnittstelle zum Abstimmen, ob der Zugriff gewährt werden soll, indem auf die Zugriffsrichtlinie verwiesen wird, die für die Ressource angegeben ist, auf die Sie zugreifen möchten. "AccessDecisionVoter" stimmt für "Gewähren", "Verweigern" oder "Zurückziehen".
Die folgende Tabelle zeigt die wichtigsten Implementierungsklassen von Spring Security.
Implementierungsklasse | Erläuterung |
---|---|
WebExpressionVoter | Spring Expression Language (SpEL)Benutzeranmeldeinformationen mit(Authentication )Und Informationen anfordern(HttpServletRequest )Eine Implementierungsklasse, die referenziert und abstimmt. |
RoleVoter | Eine Implementierungsklasse, die sich auf die Rolle und die Stimmen des Benutzers bezieht. |
RoleHierarchyVoter | Eine Implementierungsklasse, die anhand der geschichteten Rolle des Benutzers abstimmt. |
AuthenticatedVoter | Eine Implementierungsklasse, die anhand des Authentifizierungsstatus abstimmt. |
In dieser Implementierung erstellen wir eine neue Klasse mit dem Namen "MyVoter", die "AccessDecisionVoter" implementiert, und setzen nur diesen "MyVoter" auf den von "AffirmativeBased" aufgerufenen Abstimmungsprozess.
Markieren Sie basierend auf der Implementierung in [3. Implementierung der einfachen Authentifizierungs- / Autorisierungsfunktion](Nr. 3 - Implementierung der einfachen Authentifizierungs- / Autorisierungsfunktion) die hinzuzufügenden Dateien in Rot und die Dateien zum Hinzufügen oder Ändern von Code in Blau. Ich bin.
schema.sql
/*Fügen Sie den folgenden Code am Ende der Datei hinzu*/
CREATE TABLE IF NOT EXISTS access_authorization (
rolename VARCHAR(10) NOT NULL,
uri VARCHAR(255) NOT NULL,
PRIMARY KEY(rolename, uri)
);
data.sql
/*Fügen Sie den folgenden Code am Ende der Datei hinzu*/
/*Alle Rollenberechtigungen*/
INSERT INTO access_authorization(rolename, uri) VALUES ('*', '/loginForm');
INSERT INTO access_authorization(rolename, uri) VALUES ('*', '/accessDeniedPage');
INSERT INTO access_authorization(rolename, uri) VALUES ('*', '/logout');
/*ADMIN-Rollenberechtigungen*/
INSERT INTO access_authorization(rolename, uri) VALUES ('ADMIN', '/home');
INSERT INTO access_authorization(rolename, uri) VALUES ('ADMIN', '/adminPage');
/*USER Rollenberechtigungen*/
INSERT INTO access_authorization(rolename, uri) VALUES ('USER', '/home');
INSERT INTO access_authorization(rolename, uri) VALUES ('USER', '/userPage');
Ein Rollenname von "*" ist ein Platzhalter, der bedeutet, dass Zugriff auf alle Rollen </ font> gewährt.
AdminPageController.java
/*Kürzung*/
@GetMapping("/adminPage")
// @PreAuthorize("hasRole('ROLE_ADMIN')")Auskommentieren
public String adminPage() {
/*Kürzung*/
UserPageController.java
/*Kürzung*/
@GetMapping("/userPage")
// @PreAuthorize("hasRole('ROLE_USER')")Auskommentieren
public String userPage() {
/*Kürzung*/
AccessAuthorization.java
package com.example.demo.entity;
import java.io.Serializable;
public class AccessAuthorization implements Serializable {
String roleName; //Zugriff in H2DB_Von der Berechtigungstabelle"rolename"Feld zum Speichern
String uri; //Zugriff in H2DB_Von der Berechtigungstabelle"uri"Feld zum Speichern
/**
* getter, setter
*/
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}
Greifen Sie mit Spring JDBC auf die Datenbank zu.
AccessAuthorizationDao.java
package com.example.demo.repository;
import com.example.demo.entity.AccessAuthorization;
public interface AccessAuthorizationDao {
AccessAuthorization find(String roleName, String uri);
}
AccessAuthorizationDaoImpl.java
package com.example.demo.repository;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.AccessAuthorization;
@Repository
public class AccessAuthorizationDaoImpl implements AccessAuthorizationDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public AccessAuthorizationDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
*Führen Sie eine SELECT-Anweisung mit roleName und uri als Suchbedingungen aus, um zu suchen, ob sie in der Datenbank registriert ist.
* @param roleName
* @param uri
* @return AccessAuthorization
*/
@Override
public AccessAuthorization find(String roleName, String uri) {
String sql = "SELECT rolename, uri FROM access_authorization WHERE rolename = ? AND uri = ?";
//Holen Sie sich einen Benutzer
Map<String, Object> result = jdbcTemplate.queryForMap(sql, roleName, uri);
//Entitätsklasse(Benutzertyp)Umstellung auf
AccessAuthorization auth = convMapToAccessAuthorization(result);
return auth;
}
/**
*Ergebnis der Ausführung der SQL SELECT-Anweisung(Map<String, Object>)Um auf den Autorisierungstyp zuzugreifen
* @param Map<String, Object>
* @return AccessAuthorization
*/
private AccessAuthorization convMapToAccessAuthorization(Map<String, Object> map) {
AccessAuthorization auth = new AccessAuthorization();
auth.setRoleName((String) map.get("rolename"));
auth.setUri((String) map.get("uri"));
return auth;
}
}
AuthorizationService.java
package com.example.demo.service;
public interface AuthorizationService {
boolean isAuthorized(String roleName, String uri);
}
AuthorizationServiceImpl.java
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.example.demo.entity.AccessAuthorization;
import com.example.demo.repository.AccessAuthorizationDao;
@Service
public class AuthorizationServiceImpl implements AuthorizationService {
private final AccessAuthorizationDao authDao;
@Autowired
public AuthorizationServiceImpl(AccessAuthorizationDao authDao) {
this.authDao = authDao;
}
/**
*Legt fest, ob die im Argument übergebene Kombination aus Rollenname und URI zulässig ist.
* @param roleName
* @param uri
* @return boolean
*/
@Override
public boolean isAuthorized(String roleName, String uri) { // ---(1)Methode, um festzustellen, ob der Zugriff zulässig ist
if (StringUtils.isEmpty(roleName)) {
throw new IllegalArgumentException("Rollenname ist leer.");
}
if (StringUtils.isEmpty(uri)) {
throw new IllegalArgumentException("Der URI ist leer.");
}
//Eine AccessAuthorization-Ausnahme erhalten tritt auf, wenn keine AccessAuthorization vorhanden ist
try {
AccessAuthorization auth = authDao.find(roleName, uri); // ---(2)Rufen Sie eine AccessAuthorization-Instanz ab
if (auth != null) { // ---(3)Berechtigungen
return true;
} else { // ---(4)Zugriff verweigert
return false;
}
} catch (EmptyResultDataAccessException e) { // ---(5)Zugriff verweigert
return false;
}
}
}
Artikel | Erläuterung |
---|---|
(1) | Benutzerrollenname und Zugriffspfad(URI)Ist eine Methode, die bestimmt, ob der Zugriff gewährt wird. |
(2) | Übergeben Sie den Rollennamen und den URI an Dao und seien Sie eine EntitätAccessAuthorization Holen Sie sich eine Instanz von. |
(3) | AccessAuthorization Wenn Sie eine Instanz von erhalten können, stellen Sie fest, dass der Zugriff zulässig ist undtrue Gib es zurück. |
(4) | Von DaoAccessAuthorization Instanz von kann nicht abgerufen werdennull Wenn zurückgegeben wird, wird beurteilt, dass der Zugriff verweigert und der Zugriff verweigert wird.false Gib es zurück. |
MyVoter.java
package com.example.demo.voter;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import com.example.demo.service.AccountUserDetails;
import com.example.demo.service.AuthorizationService;
@Component
public class MyVoter implements AccessDecisionVoter<FilterInvocation> {
private final AuthorizationService authorizationService;
@Autowired
public MyVoter(AuthorizationService authorizationService) {
this.authorizationService = authorizationService;
}
@Override
public boolean supports(ConfigAttribute attribute) { // ---(1)Methode, um festzustellen, ob eine Abstimmung erforderlich ist oder nicht
return true;
}
@Override
public boolean supports(Class<?> clazz) { // ---(1)Methode, um festzustellen, ob eine Abstimmung erforderlich ist oder nicht
return true;
}
@Override
public int vote(Authentication authentication, FilterInvocation filterInvocation,
Collection<ConfigAttribute> attributes) { // ---(2)Eine Methode zur Abstimmung über die Gewährung des Zugriffs
HttpServletRequest request = filterInvocation.getHttpRequest(); // --- (3)Holen Sie sich HttpServletRequest
String uri = request.getRequestURI(); // --- (4)URI von Anfrage abrufen
if(authorizationService.isAuthorized("*", uri)) { // --- (5)Stellen Sie fest, ob allen Rollen Zugriff gewährt wird
return ACCESS_GRANTED;
}
Object principal = authentication.getPrincipal(); // --- (6)Erfassung von Benutzeridentifikationsinformationen
if (!principal.getClass().equals(AccountUserDetails.class)) { // ---(7)Stellen Sie fest, ob es sich bei den erfassten Identifikationsinformationen um Kontonutzerdetails handelt
return ACCESS_DENIED;
}
String roleName = ((AccountUserDetails) principal).getUser().getRoleName(); // ---(8)Holen Sie sich die Rolle des Benutzers
if(authorizationService.isAuthorized(roleName, uri)) { // ---(9)Stellen Sie fest, ob die erworbene Rolle autorisiert ist
return ACCESS_GRANTED;
}
return ACCESS_DENIED;
}
}
Artikelnummer | Erläuterung |
---|---|
(1) | Eine Methode, die sich auf den Wert des Arguments bezieht, um zu bestimmen, ob eine Abstimmung erforderlich ist oder nicht |
(2) | Eine Methode zur Abstimmung über die Gewährung des Zugriffs(Detail ist,4-2-2.Übersicht über die Berechtigungsfunktion für das tatsächlich umzusetzende Geschäft) |
(3) | HttpServletRequest Bekommen.FilterInvocation IstHttpServletRequest OderHttpServletRequest Enthält Objekte, die HTTP-Filtern zugeordnet sind, z. |
(4) | HttpServletRequest Rufen Sie die URI ab, von der aus Sie zugreifen möchten. |
(5) | Stellen Sie fest, ob der erfasste URI Zugriff auf alle Rollen gewährt. |
(6) | Holen Sie sich die Identifikationsinformationen des zugreifenden Benutzers |
(7) | Die erfassten Identifikationsinformationen sindAccountUserDetails Bestimmen Sie, ob es sich um eine Klasse handelt.Wenn sie nicht authentifiziert sind, werden die Identifikationsinformationen von der String-Klasse erfasst, sodass ein Fehler auftritt, sofern dieser Bestimmungsprozess nicht ausgeführt wird. |
(8) | AccountUserDetails Ruft die Benutzerrolle von einer Instanz von ab. |
(9) | Stellen Sie fest, ob die Rolle des Benutzers und der Pfad, auf den Sie zugreifen möchten, autorisiert sind. |
Stellen Sie den erstellten "MyVoter" so ein, dass er für Zugriffsrechte stimmt.
WebSecurityConfig.java
/*Kürzung*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AccountUserDetailsService userDetailsService;
@Autowired //Nachtrag
AccessDecisionVoter<FilterInvocation> myVoter; //Nachtrag
public AccessDecisionManager createAccessDecisionManager() { //Nachtrag
return new AffirmativeBased(Arrays.asList(myVoter)); //Nachtrag---(1)Affirmative Based wird für die Genehmigungsverarbeitung und MyVoter für die Abstimmungsverarbeitung verwendet.
} //Nachtrag
/*Kürzung*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//Autorisierungseinstellungen
http.exceptionHandling()
.accessDeniedPage("/accessDeniedPage")
.and()
.authorizeRequests()
.antMatchers("/**").authenticated() //Fix
.accessDecisionManager(createAccessDecisionManager()); //Nachtrag---(2)Wenden Sie den Autorisierungsprozess für alle Zugriffe an
/*Kürzung*/
Artikelnummer | Erläuterung |
---|---|
(1) | AccessDecisionManager Als Implementierungsklasse vonAffirmativeBased Bewerben.AccessDecisionVoter Als Implementierungsklasse vonMyVoter Bewerben.AffirmativeBased Zum Zeitpunkt der Instanziierung vonAccessDecisionVoter Mehrere Abstimmungsprozesse können durch Übergeben von Instanzen von festgelegt werden. |
(2) | Autorisierungsverarbeitung für alle Zugriffe(MyVoter Abstimmungsprozess)Ist auf Ausführung eingestellt. |
Heutzutage werden Sicherheitsprobleme häufig in den Nachrichten behandelt. Stellen Sie daher sicher, dass Sie Sicherheitsmaßnahmen in Ihrer Webanwendung implementieren. Wenn Sie eine Webanwendung mit dem Spring Framework entwickeln, sollten Sie Spring Security für Sicherheitsmaßnahmen nutzen. Sie können einfache und robuste Sicherheitsmaßnahmen anstelle von selbst erstellten Sicherheitsmaßnahmen einführen. Auf der anderen Seite ist es aus praktischer Sicht erforderlich, eine teilweise Erweiterung von Spring Security zu implementieren, da beispielsweise im Autorisierungsprozess auf die Datenbank verwiesen werden muss. Ich denke jedoch, dass dieser Artikel ein wenig gezeigt hat, wie diese erweitert werden kann. .. Die Idee, dass "auf der Grundlage eines Standardprodukts zusätzliche Funktionen, die für das Geschäft und den Betrieb erforderlich sind, zusätzlich implementiert werden", ist im tatsächlichen Geschäft wichtig, und der Autor selbst kann durch Anhörungen und das Schreiben von Artikeln lernen. Ich tat. In diesem Artikel hat Spring Security die Funktionen "Authentifizierung" und "Autorisierung" implementiert, die die Grundfunktionen von Sicherheitsmaßnahmen darstellen. Weitere Sicherheitsfunktionen bietet Spring Security. Ich habe noch viele Dinge, die ich nicht weiß, also möchte ich lernen.
Dies ist ein Artikel, der von einem Neuling (meine Synchronisation) im nächsten Abschnitt geschrieben wurde. Wenn Sie SSO (Single Sign-On) einführen möchten, lesen Sie bitte den folgenden Artikel. Erläutert das Verfahren zum Verknüpfen von Keycloak und Azure AD. Versuchen Sie eine externe ID-Verknüpfung mit Keycloak