Artikelverzeichnis
1. Autorisierung
Die sogenannte Autorisierung bedeutet, dass, wenn ein Benutzer auf eine bestimmte Ressource zugreifen möchte, geprüft werden muss, ob der Benutzer über eine solche Berechtigung verfügt. Wenn dies der Fall ist, darf er darauf zugreifen, wenn nicht, ist dies nicht zulässig.
Zweitens: Bereiten Sie sich darauf vor, Benutzer zu testen
Da wir noch keine Verbindung zur Datenbank hergestellt haben, ist der Testbenutzer weiterhin basierend auf dem Speicher konfiguriert.
Basierend auf den Benutzern des Speicherkonfigurationstests haben wir zwei Methoden: Die erste ist die Konfigurationsmethode, die wir in den vorherigen Artikeln dieser Serie wie folgt verwendet haben:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中进行配置
auth.inMemoryAuthentication()
.withUser("yolo")
.password("123").roles("admin")
.and()
.withUser("nlcs")
.password("123")
.roles("user");
}
Dies ist eine Konfigurationsmethode.
Da Spring Security eine Vielzahl von Datenquellen wie Speicher, Datenbanken, LDAP usw. unterstützt, werden diese verschiedenen Datenquellen in einer gemeinsamen UserDetailService
Schnittstelle gekapselt. Jedes Objekt, das diese Schnittstelle implementiert, kann als Authentifizierungsdatenquelle verwendet werden.
So können wir Umschreiben WebSecurityConfigurerAdapter
der userDetailsService
ein Verfahren zum Bereitstellen UserDetailService
Beispiel weiter angeordnet , um eine Vielzahl von Benutzern:
@Override
@Bean
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("yolo").password("123").roles("admin").build());
manager.createUser(User.withUsername("nlcs").password("123").roles("user").build());
return manager;
}
Drittens bereiten Sie sich darauf vor, die Schnittstelle zu testen
Der Testbenutzer ist bereit, und dann bereiten wir drei Testschnittstellen vor. wie folgt:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/admin/hello")
public String admin() {
return "admin";
}
@GetMapping("/user/hello")
public String user() {
return "user";
}
}
Für diese drei Testschnittstellen sieht unser Plan folgendermaßen aus:
(1) Es
/hello
ist eine Schnittstelle, auf die jeder zugreifen kann.
(2) Es/admin/hello
ist eine Schnittstelle, auf die nur eine Person mit einer Administratoridentität zugreifen kann.
(3)/user/hello
Eine Schnittstelle, auf die eine Person mit einer Benutzeridentität zugreifen kann.
(4) Alle Benutzer können auf Ressourcen zugreifen , der Administrator kann Zugriff
Beachten Sie, dass die vierte Spezifikation bedeutet, dass alle Personen mit Administratoridentität automatisch eine Benutzeridentität haben
Viertens Konfiguration
Als Nächstes konfigurieren wir die Berechtigungen zum Blockieren von Regeln. In der Spring Security- configure(HttpSecurity http)
Methode lautet der Code wie folgt:
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
.and()
...
...
Für die Übereinstimmungsregeln verwenden wir hier Pfadanpassungssymbole im Ant-Stil. Pfadanpassungssymbole im Ameisenstil werden in der Spring-Familie häufig verwendet, und die Übereinstimmungsregeln sind auch sehr einfach:
Die Bedeutung der obigen Konfiguration ist:
(1) Wenn die Anforderung ein Pfadformat erfüllt
/admin/**
, muss der Benutzer eine Administratorrolle haben.
(2) erfüllt, wenn die Anforderung ein Pfadformat/user/**
ist, muss der Benutzer die Benutzerrolle haben.
(3) Auf die verbleibenden Anforderungspfade in anderen Formaten kann erst nach der Authentifizierung (Anmeldung) zugegriffen werden.
Beachten Sie, dass die Reihenfolge der drei im Code konfigurierten Regeln sehr wichtig ist. Ähnlich wie bei Shiro stimmt Spring Security beim Abgleich auch von oben nach unten überein. Nach dem Abgleich wird es nicht mehr übereinstimmen.Die Reihenfolge der Abfangregeln kann also nicht falsch geschrieben werden
Auf der anderen Seite, wenn Sie eine Anforderung erzwingen, die vor antMatchers gestellt wird, wie folgt:
http.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.and()
Zu diesem Zeitpunkt, wenn das Projekt gestartet wird, wird ein Fehler gemeldet und es wird angezeigt, dass antMatchers nach anyRequest nicht hinzugefügt werden können:
Dies ist semantisch gut verstanden, anyRequest
andere Anforderungen sind bereits enthalten, und es macht keinen Sinn, wenn andere Anforderungen danach konfiguriert werden.
Semantisch verstanden anyRequest
sollte es am Ende stehen und angeben, wie die verbleibenden Anforderungen zusätzlich zu den vorherigen Abfangregeln behandelt werden sollen.
In den Blockierungsregeln für Konfigurationsklassen sehen AbstractRequestMatcherRegistry
wir folgenden Code (Abschnitt Quelle):
public abstract class AbstractRequestMatcherRegistry<C> {
private boolean anyRequestConfigured = false;
public C anyRequest() {
Assert.state(!this.anyRequestConfigured, "Can't configure anyRequest after itself");
this.anyRequestConfigured = true;
return configurer;
}
public C antMatchers(HttpMethod method, String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
}
public C antMatchers(String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
}
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
String... mvcPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
return matchers;
}
public C regexMatchers(HttpMethod method, String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(method, regexPatterns));
}
public C regexMatchers(String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
}
public C requestMatchers(RequestMatcher... requestMatchers) {
Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
return chainRequestMatchers(Arrays.asList(requestMatchers));
}
}
Anhand dieses Quellcodes können wir erkennen, dass vor Abfangregeln (einschließlich anyRequest selbst) zunächst ermittelt wird, ob anyRequest konfiguriert wurde. Wenn es konfiguriert ist, wird eine Ausnahme ausgelöst und das System kann nicht gestartet werden.
Jeder versteht also, warum anyRequest zuletzt gestellt werden muss
Fünftens, starten Sie den Test
Als nächstes starten wir das Projekt zum Testen.
Nachdem das Projekt erfolgreich gestartet wurde, melden wir uns zuerst als yolo an:
Besuchen Sie nach erfolgreicher Anmeldung die drei Schnittstellen / hello, / admin / hello und / user / hello, darunter:
(1)
/hello
Da Sie nach dem Anmelden darauf zugreifen können, wird erfolgreich auf diese Schnittstelle zugegriffen.
(2) Die/admin/hello
Administratoridentität ist erforderlich, daher schlägt der Zugriff fehl.
(3) Die/user/hello
Benutzeridentität ist erforderlich, damit der Zugriff erfolgreich ist.
Melden Sie sich auf die gleiche Weise bei nlcs an.
Sechs, Rollenvererbung
Wie bereits erwähnt, kann der Administrator auf alle Ressourcen zugreifen, auf die der Benutzer zugreifen kann. Offensichtlich verfügt unser aktueller Code noch nicht über eine solche Funktion.
Um alle Ressourcen zu implementieren, auf die der Benutzer zugreifen kann, kann der Administrator darauf zugreifen. Dazu gehört ein weiterer Wissenspunkt, der aufgerufen wirdRollenvererbung
Dies ist sehr nützlich in der tatsächlichen Entwicklung.
Die obere Ebene verfügt möglicherweise über alle Berechtigungen der unteren Ebene. Wenn die Rollenvererbung verwendet wird, ist diese Funktion sehr einfach zu implementieren. Sie müssen SecurityConfig nur den folgenden Code hinzufügen, um die Rollenvererbungsbeziehung zu konfigurieren:
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_admin > ROLE_user");
return hierarchy;
}
Beachten Sie, dass Sie in der Konfiguration das Zeichenpräfix manuell hinzufügen müssen ROLE_
. Die obige Konfiguration bedeutet ROLE_admin
automatisch ROLE_user
Berechtigung.
Nachdem die Konfiguration abgeschlossen ist, starten Sie das Projekt neu. Dieses Mal haben wir festgestellt, dass yolo auch über /user/hello
diese Schnittstelle zugreifen kann