Questions lead
Recently, many students reported that they needed to deal with data permissions in their projects, but didn’t know how to do it properly. This notebook will be aimed at this problem, give a more general and easy to expand the data permission design scheme.
The status quo
At present, the popular permission framework already supports data permission, but it needs to be configured in the interface and method, the scalability is not very good, so how to maximize the scalability?
It is easy to think of: data permission control stored in the database, in the permission interception to determine whether the interface is authorized to access, after the interface is authorized to access, then according to the configured conditions to determine whether to use the specified parameter value. (To be more advanced, check the returned result, and treat an object containing a value that is not accessible as if it is not, which is not considered in this note). So how do we do that?
Database design
Start with database table design, first define a data permission control table structure:
CREATE TABLE 'sys_acl_data' (' id 'int(11) NOT NULL,' acl_id 'int(11) NOT NULL COMMENT' 主键', 'status' tinyint(4) NOT NULL DEFAULT 1 COMMENT' status, 1: available, 0: ', 'param' varchar(20) NOT NULL DEFAULT COMMENT ', 'operation' int(11) NOT NULL DEFAULT 0 COMMENT ' Equal to, 1: greater than, 2: less than, 3: greater than or equal to, 4: less than or equal to, 5: contains, 6: between,... ', `value1` varchar(100) NOT NULL DEFAULT '0', `value2` varchar(100) NOT NULL DEFAULT '0', 'next_param_op' int(11) NOT NULL DEFAULT 0 COMMENT 'Next_param_op' int(11) NOT NULL DEFAULT 0 COMMENT Or | | ', ` seq ` tinyint (4) NOT NULL DEFAULT '0' COMMENT 'order', PRIMARY KEY (` id `), INDEX 'idx_acl_id' USING BTREE (' acl_id ') ENGINE= 'InnoDB' COMMENT 'table ';Copy the code
Describe the meaning of each field in detail:
The primary key id;
Acl_id Mapping permission point table primary key, which represents the specific permission point for each row.
Status indicates whether the current configuration is valid, which is convenient for activating or disabling temporarily.
Param is the name of the parameter to be verified. Multiple parameters can be verified in a request. If the parameters are complex, for example, including objects, the defined parameters may be in the form of multiple levels, such as A.B.C. It is recommended not to be too complex
Operation indicates the data interception rule. Numbers are equal to, greater than, less than, greater than or equal to, less than or equal to, include, and between. You can add or decrease interception rules as required
Value1 and value2 are used to form a relational expression with param and operation, for example, 1<=a<2
Next_param_op fields according to the need to use, if more than one access point to support data rules, the connection between the two rules of operation, | | &&
The SEQ field indicates the sequence of multiple data permission rules in a permission point
A valid data rule (status=1) has been configured for a permission point with id 1 (acl_id). The value of the passed parameter id (param) should be greater than that of (operation) 10 (value1).
Data permission verification logic
With the table structure, the next step is to add interfaces to update and retrieve data, and then have a page to display and add operations. I won’t take up more space here, but focus on the logical processing.
Authority course native implementation of a set of authority management part of the authority point to do the basic management and authority interception is not repeated here, specific to see the video and code can be, here focuses on how to expand data authority on the existing authority. First give the core code of URL blocking and permission verification (see this code alone without looking at the details of the course should also be able to understand a general) :
Custom filter intercept URL judgment permission core code: public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String servletPath = request.getServletPath(); Map requestMap = request.getParameterMap(); if (exclusionUrlSet.contains(servletPath)) { filterChain.doFilter(servletRequest, servletResponse); return; } SysUser sysUser = RequestHolder.getCurrentUser(); if (sysUser == null) { log.warn("someone visit {}, but no login, parameter:{}", servletPath, JsonMapper.obj2String(requestMap)); noAuth(request, response); return; } SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class); if (! sysCoreService.hasUrlAcl(servletPath)) { log.warn("{} visit {}, but no login, parameter:{}", JsonMapper.obj2String(sysUser), servletPath, JsonMapper.obj2String(requestMap)); noAuth(request, response); return; } filterChain.doFilter(servletRequest, servletResponse); return; } public Boolean hasUrlAcl(String URL) {if (isSuperAdmin()) {return true; } List<SysAcl> aclList = sysAclMapper.getByUrl(url); If (collectionUtils.isEmpty (aclList)) {return true; } List<SysAcl> userAclList = getCurrentUserAclListFromCache(); Set<Integer> userAclIdSet = userAclList.stream().map(acl -> acl.getId()).collect(Collectors.toSet()); boolean hasValidAcl = false; For (SysAcl acl: SysAcl acl: SysAcl acl: SysAcl acl: AclList) {/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (1) / / determine whether a user has a certain access permissions to point the if (acl = = null | | acl.getStatus() ! = 1) {// Permission point invalid continue; } hasValidAcl = true; if (userAclIdSet.contains(acl.getId())) { return true; / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - (2)}} the if (! hasValidAcl) { return true; / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (3)} return false. }Copy the code
From ① in the code, you can get the actual permission point to judge. When judging that a specified permission point has permission to access, data permission verification needs to be added at places ② and ③ of the code.
Now that you want to validate the parameters, you need to pass them into the hasUrlAcl method. RequestMap = request.getparameterMap (); requestMap = request.getparameterMap (); RequestMap is a list of url parameters, which is not entirely appropriate for specific POST submissions, such as passing JSON-formatted parameters in the body. How to pass parameters to methods in the actual project can be handled according to the actual definition of the project interface.
When hasUrlAcl gets the parameter and determines that the specified permission point has access, it goes to the sys_ACl_data table and queries the valid rule list according to the ACl_id. 1. Interpretation of a single rule; 2. Logic and or between multiple rules; 3. Interpretation of parameters with hierarchy (A.B.C). After this implementation, when the URL is authorized to access, there is no data rule or data rule verification, the URL is truly authorized to access.
Json /a/{id}. Json /a/{id}. In fact, this kind of interface can be supported by a slight adjustment in the course, as follows:
SysAclMapper. XML: <select id="getByUrl" parameterType="string" resultMap="BaseResultMap"> SELECT <include refid="Base_Column_List" /> FROM sys_acl WHERE url = #{url} <! -- url is not null and url ! = '' and #{url} REGEXP url--> </select>Copy the code
Url is not null and URL! = ‘and # {url} REGEXP url instead of the url = # {url}, then configure each access point when the regular to configure each access point url, such as just the url configuration access check can be configured to/a / 5 | [6]. The json. Of course, this approach has certain requirements on the regular expression of the permission administrator. In this case, when the url that meets the condition is checked, the permission point that cannot be checked is not taken out. You can configure a wildcard (/a/*.json) permission for each wildcard URL. You must ensure that a checksum containing the re is matched before the permission is granted. The details of this can be handled differently, but here is just a general idea.
At the end
About the data permission first said here, I think the above way will be relatively better in terms of scalability, implementation is not very difficult, if there is any problem, welcome to point out.
Other permission notes
Transform the authority management process of e-commerce trading background
Custom JSP tags automatically complete permission blocking for page buttons