Kann Spring Security @PreAuthorize
für Spring Controller-Methoden verwendet werden?
Antworten:
Ja, es funktioniert gut.
Sie brauchen <security:global-method-security pre-post-annotations="enabled" />
in ...-servlet.xml
. Außerdem sind CGLIB-Proxys erforderlich , sodass Ihre Controller entweder keine Schnittstellen haben sollten oder Sie diese verwenden sollten proxy-target-class = true
.
global-method-security
sollte im Kontext von DispatcherServlet ( ...-servlet.xml
) sein, nicht im Kontext von "Spring Security Application".
DispatcherServlet
Der Kontext ist ein untergeordneter Kontext des ContextLoaderListener
einen. Sie haben also unterschiedliche AOP-Konfigurationen und erfordern daher unterschiedliche Vorkommen von <global-method-security>
.
Siehe Spring Security FAQ (Schwerpunkt Mine).
In einer Spring-Webanwendung ist der Anwendungskontext, der die Spring-MVC-Beans für das Dispatcher-Servlet enthält, häufig vom Hauptanwendungskontext getrennt. Es wird häufig in einer Datei mit dem Namen myapp-servlet.xml definiert, wobei "myapp" der Name ist, der dem Spring DispatcherServlet in web.xml zugewiesen wurde. Eine Anwendung kann mehrere DispatcherServlets haben, von denen jedes seinen eigenen isolierten Anwendungskontext hat. Die Beans in diesen "untergeordneten" Kontexten sind für den Rest der Anwendung nicht sichtbar. Der übergeordnete Anwendungskontext wird vom ContextLoaderListener geladen, den Sie in Ihrer web.xml definieren, und ist für alle untergeordneten Kontexte sichtbar. In diesem übergeordneten Kontext definieren Sie normalerweise Ihre Sicherheitskonfiguration (einschließlich des Elements). Infolgedessen werden Sicherheitsbeschränkungen, die auf Methoden in diesen Web-Beans angewendet werden, nicht erzwungen. da die Beans im DispatcherServlet-Kontext nicht sichtbar sind. Sie müssen entweder die Deklaration in den Webkontext verschieben oder die zu sichernden Beans in den Hauptanwendungskontext verschieben.
Im Allgemeinen empfehlen wir, die Methodensicherheit eher auf der Serviceebene als auf einzelnen Webcontrollern anzuwenden.
Wenn Sie Pointcuts auf die Serviceebene anwenden, müssen Sie diese nur <global-method-security>
im Sicherheitskontext Ihrer App festlegen .
Wenn Sie Spring 3.1 verwenden, können Sie damit einige ziemlich coole Sachen machen. Schauen Sie sich https://github.com/mohchi/spring-security-request-mapping an . Es ist ein Beispielprojekt, das @PreAuthorize in RequestMappingHandlerMapping von Spring MVC integriert, sodass Sie Folgendes tun können:
@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
return "authenticatedHomePage";
}
@RequestMapping("/")
public String homePage() {
return "homePage";
}
Eine Anforderung für "/" ruft authenticatedHomePage () auf, wenn der Benutzer authentifiziert ist. Andernfalls wird homePage () aufgerufen.
Es ist mehr als zwei Jahre her , seit diese Frage gestellt wurde , aber wegen der Probleme hatte ich heute würde ich eher abraten verwenden @Secured
, @PreAuthorize
etc. auf @Controller
s.
Was bei mir nicht funktioniert hat, wurde @Validated
mit @Secured
Controller kombiniert :
@Controller
@Secured("ROLE_ADMIN")
public class AdministrationController {
// @InitBinder here...
@RequestMapping(value = "/administration/add-product", method = RequestMethod.POST)
public String addProductPost(@ModelAttribute("product") @Validated ProductDto product, BindingResult bindingResult) {
// ...
}
Validator wird einfach nicht ausgelöst (Spring MVC 4.1.2, Spring Security 3.2.5) und es werden keine Überprüfungen durchgeführt.
Ähnliche Probleme werden durch von Spring verwendete CGLIB-Proxys verursacht (wenn keine von einer Klasse implementierte Schnittstelle vorhanden ist, erstellt Spring einen CGLIB-Proxy; wenn die Klasse eine Schnittstelle implementiert, wird JDK-Proxy generiert - Dokumentation , hier und hier ausführlich erläutert ).
Wie in den Antworten erwähnt, die ich oben verlinkt habe, ist es nicht besser, Spring Security-Anmerkungen auf der Serviceebene zu verwenden, die normalerweise Schnittstellen implementiert (daher werden JDK-Proxies verwendet), da dies nicht zu solchen Problemen führt.
Wenn Sie Web - Controller sichern wollen, ist die bessere Idee zu verwenden <http>
und <intercept-url />
die auf spezifische URLs gebunden sind , anstatt Methoden in Controllern und ziemlich gut zu arbeiten. In meinem Fall:
<http use-expressions="true" disable-url-rewriting="true">
...
<intercept-url pattern="/administration/**" access="hasRole('ROLE_ADMIN')" />
</http>
Es gibt bereits eine Antwort darauf, wie es funktioniert, indem die XML-Konfiguration geändert wird. Wenn Sie jedoch mit einer codebasierten Konfiguration arbeiten, können Sie dasselbe erreichen, indem Sie die folgende Anmerkung über Ihre @Configuration
Klasse setzen:
@EnableGlobalMethodSecurity(prePostEnabled=true)
Zuerst müssen Sie diese Anmerkung in Ihre WebSecurityConfig einfügen, um die Anmerkungen @Pre und @Post zu aktivieren.
@EnableGlobalMethodSecurity(prePostEnabled = true)
Sie können Rollen / Berechtigungen auch wie folgt überprüfen
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
gleichwertig
@PreAuthorize("hasRole('ROLE_ADMIN')")
Sie können auch mehrere Rollen / Berechtigungen wie folgt überprüfen
@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")
Schritt 1: add @EnableGlobalMethodSecurity (prePostEnabled = true) Anmerkung in SecurityConfig Klasse. so was:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
.....
}
Schritt 2: Sie können die Annotation @PreAuthorize () in der Controller-, Service- oder Repository-Schicht hinzufügen . in einer Methoden- oder Klassenebene. zum Beispiel:
@RestController
@PreAuthorize("isAuthenticated()")
public class WebController {
@PreAuthorize("permitAll()")
@GetMapping("/")
public String home() {
return "Welcome home!";
}
@GetMapping("/restricted")
public String restricted() {
return "restricted method";
}
}
oder
@RestController
public class AdminController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin")
public String adminMethod() {
}
}