Grundlegende und systematische Geschichte Zertifizierungs- / Autorisierungsgeschichte Remember-Me-Geschichte CSRF-Geschichte Session Management Story Die Geschichte des Antwortheaders CORS-Geschichte Die Geschichte von Run-As ACL-Geschichte Teststory Sprechen Sie über die Zusammenarbeit mit MVC und Boot
Sonderedition Was Spring Security kann und was nicht
Spring Security unterstützt die Zugriffssteuerung auf Methodenebene zusätzlich zur Zugriffssteuerung durch Angabe einer URL. Es wird empfohlen, die Zugriffssteuerung auf Methodenebene auf Serviceebene durchzuführen, ohne sich ausschließlich auf die URL-basierte Zugriffssteuerung zu verlassen.
http://docs.spring.io/spring-security/site/docs/4.2.1.RELEASE/reference/htmlsingle/#request-matching
In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. [Übersetzung] In der Praxis empfehlen wir, dass Sie die Methodensicherheit auf der Serviceebene verwenden, um den Zugriff auf Ihre Anwendung zu steuern, und der Verwendung von Sicherheitsbeschränkungen, die auf Webanwendungsebene definiert sind, nicht vollständig vertrauen.
URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. [Übersetzung] Es ist schwierig zu überlegen, wie alle URLs und Anforderungen behandelt werden sollen, die Ihre Anwendung unterstützt, wenn sich die URL ändert.
Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security’s method security options. [Übersetzung] Die auf der Serviceebene definierte Sicherheit ist robuster und schwer zu umgehen [^ 5]. Daher sollten Sie immer die Methodensicherheitsoptionen von Spring Security nutzen.
[^ 5]: Sicherheitsüberprüfungen umgehen
MyMethodSecurityService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
public class MyMethodSecurityService {
@PreAuthorize("hasAuthority('ADMIN')")
public String execute() {
return "Hello Method Security!!";
}
}
MyMethodSecurityServlet.java
package sample.spring.security.servlet;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.service.MyMethodSecurityService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/method-security")
public class MyMethodSecurityServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
MyMethodSecurityService service = context.getBean(MyMethodSecurityService.class);
PrintWriter writer = resp.getWriter();
try {
writer.println(service.getMessage());
} catch (AccessDeniedException e) {
writer.println(e.getMessage());
} finally {
writer.close();
}
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<sec:global-method-security pre-post-annotations="enabled" />
<bean class="sample.spring.security.service.MyMethodSecurityService" />
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="user" password="user" authorities="USER" />
<sec:user name="admin" password="admin" authorities="ADMIN" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
Java Configuration
MySpringSecurityConfig.java
package sample.spring.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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 sample.spring.security.service.MyMethodSecurityService;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
@Bean
public MyMethodSecurityService myMethodSecurityService() {
return new MyMethodSecurityService();
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("user")
.authorities("USER")
.and()
.withUser("admin")
.password("admin")
.authorities("ADMIN");
}
}
Oben ist, wenn Sie sich als "Benutzer" anmelden, und unten, wenn Sie sich als "Administrator" anmelden.
applicationContext.xml
<sec:global-method-security pre-post-annotations="enabled" />
MySpringSecurityConfig.java
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
--Um die Methodensicherheit zu aktivieren
MyMethodSecurityService.java
@PreAuthorize("hasAuthority('ADMIN')")
public String getMessage() {
return "Hello Method Security!!";
}
MyMethodSecurityService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PostAuthorize;
public class MyMethodSecurityService {
@PostAuthorize("returnObject == 'hoge'")
public String getMessage(String parameter) {
System.out.println("parameter = " + parameter);
return parameter;
}
}
MyMethodSecurityServlet.java
package sample.spring.security.servlet;
...
@WebServlet("/method-security")
public class MyMethodSecurityServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
MyMethodSecurityService service = context.getBean(MyMethodSecurityService.class);
PrintWriter writer = resp.getWriter();
try {
String parameter = req.getParameter("parameter");
writer.println(service.getMessage(parameter));
} catch (AccessDeniedException e) {
writer.println(e.getMessage());
} finally {
writer.close();
}
}
}
Die Einstellungen sind die gleichen wie bei [vorherige](# method-security-pre-authorize).
Zugriff auf / method-security? Parameter = hoge
Serverausgabe
parameter = hoge
Zugriff auf / method-security? Parameter = fuga
Serverausgabe
parameter = fuga
MyMethodSecurityService.java
@PostAuthorize("returnObject == 'hoge'")
public String getMessage(String parameter) {
System.out.println("parameter = " + parameter);
return parameter;
}
MyMethodSecurityService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
public class MyMethodSecurityService {
@PreAuthorize("#strValue == 'aaa' and #intValue == 1")
public String getMessage(String strValue, int intValue) {
return "strValue=" + strValue + ", intValue=" + intValue;
}
}
MyMethodSecurityServlet.java
package sample.spring.security.servlet;
...
@WebServlet("/method-security")
public class MyMethodSecurityServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
MyMethodSecurityService service = context.getBean(MyMethodSecurityService.class);
PrintWriter writer = resp.getWriter();
try {
String strValue = req.getParameter("strValue");
int intValue = Integer.parseInt(req.getParameter("intValue"));
writer.println(service.getMessage(strValue, intValue));
} catch (AccessDeniedException e) {
writer.println(e.getMessage());
} finally {
writer.close();
}
}
}
Zugriff auf / method-security? StrValue = abc & intValue = 1
Zugriff auf / method-security? StrValue = aaa & intValue = 1
MyMethodSecurityService.java
@PreAuthorize("#strValue == 'aaa' and #intValue == 1")
public String getMessage(String strValue, int intValue) {
Der Parametername der Methode kann nicht durch Reflektion übernommen werden, wenn es sich um Java 7 oder weniger handelt. Wenn für Java 8 und höher zum Zeitpunkt der Kompilierung die Option "-parameters" angegeben wird, können Parameternamen durch Reflektion übernommen werden. /api/java/lang/reflect/Parameter.html).
Spring bietet Lösungen für verschiedene Parameternamen, um diese Situationen zu bewältigen.
python
package sample.spring.security.service;
import org.springframework.security.access.method.P;
import org.springframework.security.access.prepost.PreAuthorize;
public class MyMethodSecurityService {
@PreAuthorize("#strValue == 'aaa' and #intValue == 1")
public String getMessage(@P("strValue") String strValue, @P("intValue") int intValue) {
return "strValue=" + strValue + ", intValue=" + intValue;
}
}
Eine Anmerkung mit dem Namen "@ P" wird bereitgestellt. Jetzt können Sie den Parameter mit Anmerkungen versehen und den Parameternamen mit "Wert" angeben, um den Parameternamen per Anmerkung zu erhalten.
Die Implementierungsklasse ist "AnnotationParameterNameDiscoverer".
Verfügbar für Java 8 und höher, wenn zur Kompilierungszeit mit der Option -parameters
kompiliert wird.
Die Implementierungsklasse ist "StandardReflectionParameterNameDiscoverer".
Um diese Funktion verwenden zu können, müssen beim Kompilieren Debug-Informationen generiert werden. Insbesondere ist es notwendig, mindestens "vars" mit der Option "-g" anzugeben.
Wenn Sie mit Gradle kompilieren, ist diese Option übrigens standardmäßig aktiviert, sodass Sie diese Funktion verwenden können, ohne sich darüber Gedanken machen zu müssen.
Die Implementierungsklasse ist "LocalVariableTableParameterNameDiscoverer".
Die obigen Funktionen werden in der Reihenfolge "Annotation" -> "Reflection" -> "Class File Analysis" angewendet, und der zuerst gefundene Name wird verwendet.
Recommended Posts