Realization of permission model based on shiro

1. shiro

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, password, and session management. With Shiro's easy to understand API, you can quickly and easily access any application, from the smallest mobile application to the largest network and enterprise application.

  • Authentication: user identification, often referred to as user "login"
  • Authorization: access control. For example, whether a user has permission to use an operation.
  • Session Management: user specific Session Management, even in non web or EJB applications.
  • Encryption: it is easy to use while encrypting the data source with encryption algorithm.

Shiro architecture contains three main concepts: Subject,SecurityManager and Realm. The following figure shows how these components interact, which we will describe in turn below.

2. shiro authority control

Shiro controls permissions

Four main ways:

a. In the program, the authority is controlled by Subject programming

b. Configure Filter to implement URL level coarse-grained permission control

  • xxx.html *= anon (not logged in for access)
  • xxx.html *= authc (must be logged in to access)
  • xxx.html *= perms [permissions] (specific permissions are required to access)
  • xxx.html *= roles (requires a specific role to access)

c. Configure agent and implement fine-grained permission control based on annotation

  • @Requirespermissions require specific permissions to access
  • @Requiresroles require a specific role to access
  • @Requireauthentication requires authentication to access

d. Using shiro custom label to control page display authority

  • < shiro:authenticated >Log in to access
  • < shiro:hasPermission name= "ABC" > requires specific permissions to access
  • < shiro:hasRole name= "ABC" > requires specific roles to access

3. Authority Database Model

Among them, users and roles are many to many, roles and menu permissions are many to many.

Roles and departments are many to many, which is mainly to access data permissions of which departments according to this role.

Data permission implementation

Define data filtering comments

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataFilter {
    /**  Alias of table */
    String tableAlias() default "";

    /**  true: Without Data permission of the Department, you can also query your own data */
    boolean user() default true;

    /**  true: Have data permission of sub department */
    boolean subDept() default false;

    /**  Department ID */
    String deptId() default "dept_id";

    /**  User ID */
    String userId() default "user_id";
}

Dynamic SQL intercept injection

@Aspect
@Component
public class DataFilterAspect {
    @Autowired
    private SysDeptService sysDeptService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysRoleDeptService sysRoleDeptService;

    @Pointcut("@annotation(com.xb.common.annotation.DataFilter)")
    public void dataFilterCut() {

    }

    @Before("dataFilterCut()")
    public void dataFilter(JoinPoint point) throws Throwable {
        Object params = point.getArgs()[0];
        if(params != null && params instanceof Map){
            SysUserEntity user = ShiroUtils.getUserEntity();

            //Data filtering if not super administrator
            if(user.getUserId() != Constant.SUPER_ADMIN){
                Map map = (Map)params;
                map.put(Constant.SQL_FILTER, getSQLFilter(user, point));
            }

            return ;
        }

        throw new RRException("Data permission interface, only Map Type parameter, and cannot be NULL");
    }

    /**
     * Get SQL for data filtering
     */
    private String getSQLFilter(SysUserEntity user, JoinPoint point){
        MethodSignature signature = (MethodSignature) point.getSignature();
        DataFilter dataFilter = signature.getMethod().getAnnotation(DataFilter.class);
        //Get alias of table
        String tableAlias = dataFilter.tableAlias();
        if(StringUtils.isNotBlank(tableAlias)){
            tableAlias +=  ".";
        }

        //Department ID list
        Set<Long> deptIdList = new HashSet<>();

        //Department ID list corresponding to user role
        List<Long> roleIdList = sysUserRoleService.queryRoleIdList(user.getUserId());
        if(roleIdList.size() > 0){
            List<Long> userDeptIdList = sysRoleDeptService.queryDeptIdList(roleIdList.toArray(new Long[roleIdList.size()]));
            deptIdList.addAll(userDeptIdList);
        }

        //User sub department ID list
        if(dataFilter.subDept()){
            List<Long> subDeptIdList = sysDeptService.getSubDeptIdList(user.getDeptId());
            deptIdList.addAll(subDeptIdList);
        }

        StringBuilder sqlFilter = new StringBuilder();
        sqlFilter.append(" (");

        if(deptIdList.size() > 0){
            sqlFilter.append(tableAlias).append(dataFilter.deptId()).append(" in(").append(StringUtils.join(deptIdList, ",")).append(")");
        }

        //Without Data permission of the Department, you can also query your own data
        if(dataFilter.user()){
            if(deptIdList.size() > 0){
                sqlFilter.append(" or ");
            }
            sqlFilter.append(tableAlias).append(dataFilter.userId()).append("=").append(user.getUserId());
        }

        sqlFilter.append(")");

        if(sqlFilter.toString().trim().equals("()")){
            return null;
        }

        return sqlFilter.toString();
    }
}

service method usage example

    @DataFilter(subDept = true, user = false, tableAlias = "t1")
    public List<SysDeptEntity> queryList(Map<String, Object> params){
        return baseMapper.queryList(params);
    }

Add SQL dynamically_ fliter

	<select id="queryList" resultType="com.xb.modules.sys.entity.SysDeptEntity">
		select t1.*,(select t2.name from sys_dept t2 where t2.dept_id=t1.parent_id)parentName from sys_dept t1 where 
			t1.del_flag = 0
		<if test="sql_filter != null">
			and ${sql_filter}
		</if>
	</select>

reference resources: https://gitee.com/pengchua/webframework_merge/tree/master/web-framework/xb-admin

Tags: Programming Shiro Session SQL Apache

Posted on Sat, 23 May 2020 03:24:28 -0700 by lulubell