参考
Spring Security 官方文档
http://www.concretepage.com/spring/spring-security/preauthorize-postauthorize-in-spring-security
方法调用安全
对应的注解@EnableGlobalMethodSecurity,该注解放在GlobalMethodSecurityConfiguration的子类上方
@EnableGlobalMethodSecurity(prePostEnabled = true)
使用的Voter
org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter
有俩对对应的注解
@PreAuthorize 决定方法是否可以被调用
@PostAuthorize 决定方法是否可以返回该值
@PreFilter
@PostFilter
如下:
package com.jiangchong.methodsecurity; import org.springframework.security.access.method.P; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; public interface IBookService { @PreAuthorize("hasRole('ROLE_ADMIN')") public void addBook(Book book); // PostAuthorize,决定这个值是否可以被返回,使用returnObject /* * Less commonly, you may wish to perform an access-control check after the * method has been invoked. This can be achieved using the @PostAuthorize * annotation. To access the return value from a method, use the built-in * name returnObject in the expression. */ @PostAuthorize("returnObject.owner == authentication.name") public Book getBook(); // PreAuthorize,决定这个方法是否可以被调用 /* * @P单个参数的方法 */ @PreAuthorize("#b.owner == authentication.name") public void deleteBook(@P("b") Book book); /* * @Param放在至少有一个参数的方法的上 * * @PreAuthorize("#n == authentication.name") Contact * findContactByName(@Param("n") String name) */ // springEL /* * @PreAuthorize("#contact.name == authentication.name") public void * doSomething(Contact contact); */ }
测试的Demo,基于Spring Boot
Pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jiangchong</groupId> <artifactId>methodsecurity</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>methodsecurity</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> </dependencies> </project>
App.class
package com.jiangchong.methodsecurity; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * */ @RestController @SpringBootApplication public class App { @Autowired public IBookService bookService; public static void main(String[] args) { SpringApplication.run(App.class, args); } @RequestMapping("/") public Map<String, String> test() { Book b1 = new Book("A", "admin"); bookService.addBook(b1); bookService.getBook(); System.out.println("user return"); Book b2 = new Book("B", "user"); bookService.deleteBook(b2); return null; } /* * @RequestMapping("/admin") public Map<String, String> testAdmin() { * Map<String, String> map = new HashMap<>(); map.put("admin", "admin"); * return map; } * * @RequestMapping("/user") public Map<String, String> testUser(String name) * { Map<String, String> map = new HashMap<>(); map.put("user", "user"); * return map; } * * @RequestMapping("/resource/test") public Map<String, String> * testResouce() { Map<String, String> map = new HashMap<>(); * map.put("test", "resource"); return map; } */ }
Book.class
package com.jiangchong.methodsecurity; public class Book { private String name; private String owner; public Book(String name, String owner) { this.name = name; this.owner = owner; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
BookService.class
package com.jiangchong.methodsecurity; import org.springframework.stereotype.Service; @Service public class BookService implements IBookService { @Override public void addBook(Book book) { System.out.println("You have successfully added book."); } @Override public Book getBook() { Book book = new Book("B", "user"); System.out.println("return " + book.getOwner()); return book; } @Override public void deleteBook(Book book) { System.out.println("Books deleted"); } }
IBookService
package com.jiangchong.methodsecurity; import org.springframework.security.access.method.P; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; public interface IBookService { @PreAuthorize("hasRole('ROLE_ADMIN')") public void addBook(Book book); // PostAuthorize,决定这个值是否可以被返回,使用returnObject /* * Less commonly, you may wish to perform an access-control check after the * method has been invoked. This can be achieved using the @PostAuthorize * annotation. To access the return value from a method, use the built-in * name returnObject in the expression. */ @PostAuthorize("returnObject.owner == authentication.name") public Book getBook(); // PreAuthorize,决定这个方法是否可以被调用 /* * @P单个参数的方法 */ @PreAuthorize("#b.owner == authentication.name") public void deleteBook(@P("b") Book book); /* * @Param放在至少有一个参数的方法的上 * * @PreAuthorize("#n == authentication.name") Contact * findContactByName(@Param("n") String name) */ // springEL /* * @PreAuthorize("#contact.name == authentication.name") public void * doSomething(Contact contact); */ }
MethodSecurityConfig
package com.jiangchong.methodsecurity; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(); } }
WebSecurityConfig
package com.jiangchong.methodsecurity; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().formLogin() .loginProcessingUrl("/login").permitAll(); } public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resource/**"); } protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("admin").password("admin") .roles("ADMIN").and().withUser("user").password("user") .roles("USER"); } }
Book b1 = new Book("A", "admin");
bookService.addBook(b1);
bookService.getBook();
System.out.println("user return");
Book b2 = new Book("B", "user");
bookService.deleteBook(b2);
这些调用序列,只要有一个不满足权限,后面的方法不会再调用