1. Überblick über Spring Security
1. Einführung in Spring Security
Spring Security ist ein Sicherheitsframework, das deklarative Sicherheitszugriffskontrolllösungen für Spring-basierte Unternehmensanwendungssysteme bereitstellt. Es stellt eine Reihe von Beans bereit, die im Spring-Anwendungskontext konfiguriert werden können und dabei die Funktionen Spring IoC (Inversion of Control), DI (Dependency Injection) und AOP (Aspect Oriented Programming) vollständig nutzen, um Deklarationen für das Anwendungssystem bereitzustellen Die umfassende Sicherheitszugriffskontrollfunktion reduziert den Aufwand, eine große Menge sich wiederholenden Codes für die Sicherheitskontrolle des Unternehmenssystems zu schreiben.
Spring Security bietet die folgenden Funktionen:
- Umfassende und skalierbare Unterstützung für Authentifizierung und Autorisierung
- Schützen Sie sich vor Angriffen wie Sitzungsfixierung, Click-Hijacking, Cross-Site-Request-Forgery usw.
- Unterstützt die Servlet-API-Integration
- Unterstützt die Integration mit Spring Web MVC
Die Beziehung zwischen Spring, Spring Boot und Spring Security ist in der folgenden Abbildung dargestellt:
2. Schnellstart mit Spring Security
2.1. Einführung von Abhängigkeiten
<!--springboot整合security坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Oder überprüfen Sie es beim Erstellen des Springboot-Projekts
2.2. Erstellen Sie einen Controller
@RestController
public class HelloController {
@GetMapping("hello")
public String hello(){
return "Hello Spring security";
}
}
2.3. Starten Sie das Projekt
Besuchen Sie: http://localhost:8080/hello. Das Ergebnis ist eine Anmeldeseite. Tatsächlich wurde unsere Anfrage zu diesem Zeitpunkt geschützt. Wenn wir darauf zugreifen möchten, müssen wir uns zuerst anmelden.
Spring Security stellt standardmäßig einen Benutzer mit dem Namen user bereit , dessen Passwort in der Konsole zu finden ist.
4. Konfiguration der Spring Security-Authentifizierung
1、WebSecurityConfigurerAdapter
Natürlich können Sie es auch über eine Konfigurationsklasse konfigurieren, eine zu erbende Konfigurationsklasse erstellen und eine benutzerdefinierte Benutzername- und Kennwortanmeldung implementieren.
/**
* Spring Security配置类
* 在springboot2.7 后WebSecurityConfigurerAdapter弃用了,用2.5.4
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 对密码进行加密。123 是密码明文,现在 Spring Security 强制性要求『不允许明文存储密码』。
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode("123");
auth.inMemoryAuthentication().withUser("tom").password(password).roles("admin");
}
}
Für Springsecurity ist es zwingend erforderlich, einen Passwortverschlüsseler (PasswordEncoder) zu verwenden, um das ursprüngliche Passwort (Registrierungspasswort) zu verschlüsseln. Daher führt das Vergessen, einen PasswordEncoder anzugeben, There is no PasswordEncoder mapped for the id "null"
während der Ausführung zu einer Ausnahme.
Dies liegt daran, dass wir beim Verschlüsseln von Kennwörtern das BCryptPasswordEncoder- Objekt verwenden und Spring Security den Verschlüsseler während des Kennwortvergleichsprozesses nicht selbst „erstellt“. Daher müssen wir den Verschlüsseler im Spring IoC-Container konfigurieren und erstellen. Singleton-Objekt dafür direkt zu verwenden.
Daher müssen wir auch das Singleton-Objekt des Verschlüsselers im Container konfigurieren und erstellen (das Neue oben kann theoretisch in Injektion umgewandelt werden) und die Spring-Sicherheitskonfigurationsklasse ändern
/**
* Spring Security配置类
* 在springboot2.7后WebSecurityConfigurerAdapter弃用了,用2.5.4
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 对密码进行加密。123 是密码明文,现在 Spring Security 强制性要求『不允许明文存储密码』。
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode("123");
//此方法是在代码中写死的,无法从数据库中获取,所以基本不适用
auth.inMemoryAuthentication().withUser("tom").password(password).roles("admin");
}
/**
* 将PasswordEncoder注入到ioc容器
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Der integrierte Passwort-Encoder von Spring Security umfasst:
Name des Verschlüsselungsalgorithmus | PasswortEncoder |
---|---|
NEIN | NoOpPasswordEncoder.getInstance() |
SHA256 | neuer StandardPasswordEncoder() |
BCRYPT (offizielle Empfehlung) | neuer BCryptPasswordEncoder() |
LDAP | neuer LdapShaPasswordEncoder() |
PBKDF2 | neuer Pbkdf2PasswordEncoder() |
SKRYPT | neuer SCryptPasswordEncoder() |
MD4 | neuer Md4PasswordEncoder() |
MD5 | neuer MessageDigestPasswordEncoder („MD5“) |
SHA_1 | neuer MessageDigestPasswordEncoder („SHA-1“) |
SHA_256 | neuer MessageDigestPasswordEncoder („SHA-256“) |
2. Informationen aus der Datenbank abrufen
- Abhängigkeiten in POM hinzufügen
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
- Konfigurieren Sie in yml
server:
port: 8070
spring:
# 配置数据源信息
datasource:
# 配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
# 配置连接数据库信息
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: 123456
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.woniu.entity
configuration:
# 配置MyBatis日志,执行sql的时候,将sql打印到控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- Erstellen Sie unter dem Entitätspaket eine neue Entitätsklasse Users. Es wird empfohlen, User nicht zu verwenden, da es in der UserDetails-Schnittstelle eine Implementierungsklasse namens User gibt, die mehr als einmal zum falschen Paket führt.
package com.woniu.entity;
import lombok.Data;
import java.util.List;
@Data
public class Users {
private Integer id;
private String username;
private String account;
private String password;
private List<String> anths;//该用户拥有的权限
}
- Erstellen Sie eine neue Tabelle in der Datenbank:
Benutzertabelle,
Zuordnungstabelle,
Berechtigungstabelle
- Erstellen Sie UsersMapper unter dem Mapper-Paket
package com.woniu.dao;
import com.woniu.entity.Users;
public interface UsersDao {
/**
* 通过账号获取用户信息
* @param account
* @return
*/
Users getUserInfoByAccount(String account);
}
- Erstellen Sie unter „Ressourcen“ ein neues Mapper-Paket und erstellen Sie „UsersMapper.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.woniu.mapper.UsersMapper">
<resultMap id="userMap" type="Users">
<result column="id" property="id"></result>
<result column="username" property="username"></result>
<result column="account" property="account"></result>
<result column="password" property="password"></result>
<collection property="anths" ofType="java.lang.String">
<result column="anth_code"></result>
</collection>
</resultMap>
<select id="getUserInfoByAccount" resultMap="userMap">
SELECT
us.id,
us.username,
us.account,
us.password,
ta.anth_code
FROM
t_users us
left join t_user_anth tua on us.id = tua.user_id
left join t_anth ta on tua.anth_id = ta.id
where account = #{account}
</select>
</mapper>
-
Erstellen Sie unter dem Servicepaket eine MyUserDetailsService-Klasse, um die UserDetailsService-Schnittstelle zu implementieren
/** * spring security认证业务类 */ @Service public class MyUserDetailsService implements UserDetailsService { @Autowired private UsersMapper usersMapper; @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //调用dao到数据库中根据username查找用户信息 Users users = usersMapper.getByUserName(username); String anths = String.join(",", userInfo.getAnths()); try { //将查找到的用户帐号与密码保存到Security的User对象中由Security进行比对 return new User(users.getUsername(), passwordEncoder.encode(users.getPassword()), //配置登录用户有哪些角色和权限,此处模拟直接写死 AuthorityUtils.commaSeparatedStringToAuthorityList(anths); }catch (Exception e){ throw new UsernameNotFoundException("用户"+username+"不存在"); } } }
-
Ändern Sie die Spring-Sicherheitskonfigurationsklasse
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyUserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } /** * 将PasswordEncoder注入到ioc容器 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
-
Starten Sie das Projekt und testen Sie es im Browser