preface
In the previous chapters, brother 11 has introduced many functions of Spring Security. Among these functions, we know that its core function is authentication + authorization. Previously, we have implemented authentication and authorization functions based on memory model, default database model and user-defined database model respectively. However, in either way, we restrict the interception of an interface by writing a SecurityConfig configuration class. In the configure(HttpSecurity http) method of this class, we use HTTP. Authorizerequests(). Antmatchers( "/ admin / * *")... Such code for permission control.
Although this permission control method can also intercept or release some interfaces, it is not flexible enough. In fact, there are other ways for Spring Security to intercept or release interfaces. Please learn from me next!
1, Permission control mode
In Spring Security, we can either use the default method provided by Spring Security for authorization or customize authorization. In short, the implementation methods of permission control in Spring Security are flexible. In Spring Security, there are four common permission control methods for intercepting or releasing interfaces:
- Using Ant expression to realize permission control;
- Using authorization annotation combined with SpEl expression to realize permission control;
- Using filter annotation to realize permission control;
- Use dynamic permission to realize permission control.
We will explain and implement the four permission control methods mentioned above.
2, Using Ant expression to realize permission control
The permission control method using Ant expression is the permission control method we have been using before. Before code implementation, I will briefly analyze the underlying implementation of this method.
1. Permission control method in spring security
In Spring Security, there is a SecurityExpressionOperations interface, which defines a series of methods for setting user permissions, as shown in the following figure:
The functions of these methods in the SecurityExpressionOperations interface are shown in the following figure:
2. Permission control granularity in spring security
This interface has a SecurityExpressionRoot subclass, which provides expression based permission control implementation. This SecurityExpressionRoot has two implementation subclasses, which are respectively used to implement URL Web interface granularity permission control and method granularity permission control, as shown in the following figure:
3. Code implementation
From the above section, we know that Spring Security supports two kinds of granularity of permission control, namely URL Web interface granularity and method granularity. The so-called Ant expression authorization control method here is to control the access permission of URL interface through Ant expression.
Then, if we need to control the URL interface granularity, we can implement it according to the following code:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**") .hasRole("ADMIN") .antMatchers("/user/**") .hasRole("USER") .antMatchers("/visitor/**") .permitAll() .anyRequest() .authenticated() .and() .formLogin() .permitAll() .and() //Protection against cross domain Request Forgery ---- > CSRF: a means to attack users by using cookie s with login status .csrf() .disable(); }
In the above code, the path in / admin / * * format can be accessed only by admin role, the path in / user / * * format can be accessed only by user role, the path in / visitor / * * format can be accessed directly, and other interface paths can be accessed only after logging in.
3, Using authorization annotation combined with SpEl expression to realize permission control
1. Authorization note
In addition to using the Ant expression above for authorization implementation, we can also add authorization annotations to the method to control permissions. There are three commonly used authorization annotations:
- @PreAuthorize: perform permission check before method execution;
- @PostAuthorize: perform permission check after the method is executed;
- @Secured: similar to @ PreAuthorize.
2. Code implementation
To use the above three authorization annotations for permission control, we first need to use the @ EnableGlobalMethodSecurity annotation to enable the authorization annotation function. The code is as follows:
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { ... ... }
Then, the authorization annotation is used for permission control on the specific interface method, and the code is as follows:
@RestController public class UserController { @Secured({"ROLE_USER"}) //@PreAuthorize("principal.username.equals('user')") @GetMapping("/user/hello") public String helloUser() { return "hello, user"; } @PreAuthorize("hasRole('ADMIN')") @GetMapping("/admin/hello") public String helloAdmin() { return "hello, admin"; } @PreAuthorize("#age>100") @GetMapping("/age") public String getAge(@RequestParam("age") Integer age) { return String.valueOf(age); } @GetMapping("/visitor/hello") public String helloVisitor() { return "hello, visitor"; } }
It can be seen that this writing method is obviously more flexible and convenient than using Ant expression for permission control, so this writing method is very commonly used in development.
4, Using filter annotation to realize permission control
1. Introduction to filter notes
Spring Security also provides two other annotations, namely @ PreFilter and @ PostFilter, which can filter the parameters or return values of collection types. When using @ PreFilter and @ PostFilter, Spring Security will remove the elements whose corresponding expression result is false.
2. Usage of @ postfilter
@PostFilter annotation is mainly used to filter the returned values of collection types. filterObject is a built-in expression in @ PostFilter, which represents the element objects in the collection.
@Slf4j @RestController public class FilterController { /** * Only the user element with even id in the result is returned. * filterObject Is a built-in expression in @ PreFilter and @ PostFilter that represents the current object in the collection. */ @PostFilter("filterObject.id%2==0") @GetMapping("/users") public List<User> getAllUser() { List<User> users = new ArrayList<>(); for (int i = 0; i < 10; i++) { users.add(new User(i, "yyg-" + i)); } return users; } }
When we start the browser to test, we can see that only elements with even id are returned in the test interface.
3. Usage of @ prefilter
You can also use @ PreFilter to filter parameters of collection type. When there are multiple parameters of collection type in the method marked with @ PreFilter, you can specify which parameter is currently filtered through the filterTarget attribute of @ PreFilter; and filterObject is a built-in expression in @ PreFilter, which represents the element objects in the collection.
To facilitate testing, we perform filtering operations in the Service layer and then call them in the Controller layer.
Method definition in FilterService class:
@Slf4j @Service public class FilterService { /** * When there are multiple collection type parameters in the method marked with @ PreFilter, * You can specify which parameter is currently filtered through the filterTarget property of @ PreFilter. */ @PreFilter(filterTarget = "ids", value = "filterObject%2==0") public List<Integer> doFilter(List<Integer> ids, List<User> users) { log.warn("ids=" + ids.toString()); log.warn("users=" + users.toString()); return ids; } }
Define a test interface in the Controller:
@Slf4j @RestController public class FilterController { /** * Only the user element with even id in the result is returned. * filterObject Is a built-in expression in @ PreFilter and @ PostFilter that represents the current object in the collection. */ @PostFilter("filterObject.id%2==0") @GetMapping("/users") public List<User> getAllUser() { List<User> users = new ArrayList<>(); for (int i = 0; i < 10; i++) { users.add(new User(i, "yyg-" + i)); } return users; } @Autowired private FilterService filterService; @GetMapping("/users2") public List<Integer> getUserInfos() { List<Integer> ids = new ArrayList<>(); for (int i = 0; i < 10; i++) { ids.add(i); } List<User> users = new ArrayList<>(); for (int i = 0; i < 10; i++) { users.add(new User(i, "yyg-" + i)); } return filterService.doFilter(ids, users); } }
When we start the browser to test, we can see that only elements with even id are returned in the test interface.
4. Code structure
The following figure shows the code structure of the above case. Please refer to the implementation:
5, Using dynamic permission to realize permission control
We know that for a standard RABC, the permission system needs to support dynamic configuration. By default, Spring Security stipulates permissions in the code. In real business scenarios, it usually needs to support dynamic configuration of role access permissions, that is, configure the access role corresponding to the url at runtime. The dynamic permissions in Spring Security are mainly implemented by rewriting interceptors and decision makers. The simplest way is to customize a Filter to complete permission judgment. In fact, the code involved here basically has little to do with Spring Security. It is mainly implemented in the traditional Filter. I won't describe it here. Interested students can implement it by themselves!
So far, I'll introduce you to the four ways of permission control in Spring Security. You can choose according to your project needs.