Kann Spring Security @ SpringAuthorize für Spring Controller-Methoden verwenden?

Antworten:

69

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.

axtavt
quelle
1
Ich habe das in meinen Spring Security-Anwendungskontext eingefügt (ich hatte es tatsächlich schon), aber Spring macht nichts mit Controllern, die @Controller verwenden. Muss ich etwas Besonderes tun, damit dies über das hinaus funktioniert, was Sie gesagt haben? In
egervari
13
Ich sagte, global-method-securitysollte im Kontext von DispatcherServlet ( ...-servlet.xml) sein, nicht im Kontext von "Spring Security Application".
Axtavt
2
Sie werden nicht zusammengeführt. DispatcherServletDer Kontext ist ein untergeordneter Kontext des ContextLoaderListenereinen. Sie haben also unterschiedliche AOP-Konfigurationen und erfordern daher unterschiedliche Vorkommen von <global-method-security>.
Axtavt
1
Danke, axtavt. Du hast meinen Tag gerettet. Im Frühjahrsdokument wurde nicht erwähnt, dass <security: global-method-security pre-post-annotations = "enabled" /> in ...- servlet.xml enthalten sein sollte. Ich habe es auch in den Kontext einer Sicherheitsanwendung gestellt und es hat nicht funktioniert. Sobald es nach ...- servlet.xml verschoben wurde, begann es zu funktionieren. Ich habe noch eine Frage, wann <security: global-method-security> in den Kontext einer Sicherheitsanwendung gestellt werden soll.
Georgie Porgie
1
@Georgie: Es sollte in jedem Kontext platziert werden, in dem Sie Beans deklariert haben, auf die Sie Sicherheitsanmerkungen anwenden möchten.
Axtavt
26

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 .

Tomasz
quelle
Ich habe versucht, @PreAuthorize im Controller zu verwenden, habe nicht funktioniert und funktioniert, nachdem ich zur Serviceschicht gewechselt bin.
MarCrazyness
17

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.

Andy
quelle
10

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, @PreAuthorizeetc. auf @Controllers.

Was bei mir nicht funktioniert hat, wurde @Validatedmit @SecuredController 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>
dominik
quelle
6

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 @ConfigurationKlasse setzen:

@EnableGlobalMethodSecurity(prePostEnabled=true)
OlgaMaciaszek
quelle
1

Um die Antwort von Andy zu erweitern, können Sie Folgendes verwenden:

@PreAuthorize("hasRole('foo')")

um die spezifische Rolle zu überprüfen.

Atul
quelle
0

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 ...")
Siddhey Sankhe
quelle
Sind Sie sicher, dass es gleichwertig ist? Ich denke, der Ausdruck hasRole fügt dem angegebenen Argument automatisch das Präfix ROLE_ hinzu.
zeratul021
0

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() {
   }
}
ehsan maddahi
quelle