Series directory

SpringSecurity rights management system actual combat – one, project introduction and development environment preparation

SpringSecurity rights management system practice – two, log, interface documents and other implementation

SpringSecurity rights management system practice – three, the main page and interface implementation

SpringSecurity rights management system actual combat – four, integration of SpringSecurity (part 1)

SpringSecurity rights management system practice – five, integration of SpringSecurity (under)

SpringSecurity authority management system combat – six, SpringSecurity integration JWT

SpringSecurity rights management system practice – seven, deal with some problems

SpringSecurity rights management system practice – eight, AOP record user logs, abnormal logs

SpringSecurity rights management system actual combat – nine, data rights configuration

preface

Part of this chapter is the most tired part I write now, tired is tired in the logical processing, because there are many tables involved in the operation, to deal with the logic of this part is very troublesome

It also led me to some naming problems at the beginning of the database design (which I will solve later).

For example, the id in the user table is better to use user_id, whereas I used ID before. What problems does this cause? Role_user = roLE_user; roLE_user = roLE_user; roLE_user = roLE_user; roLE_user = roLE_user; roLE_user = roLE_user; roLE_user = ROLE_user; roLE_user = ROLE_user; roLE_user = ROLE_user; roLE_user = ROLE_user; A bloody lesson, people should pay attention.

This article is just to give a thought, the content and logic are too complex, we need to modify the original part, we can not paste the code step by step like before

I hope you can give me more star support. Your likes are my motivation to maintain it

giteeandgithubUpdate the source code synchronously

Attached: Alibaba database design specification

What is data permission

Specifically, permission design can be divided into functional permission and data permission. Functional permissions are the interfaces that a role can operate, and data permissions are the data that a role can access.

To put it figuratively, if you have a company, there are many departments in the company, and there are many employees in the department, and the data permission is to let the employees in a certain department only have access to the information of employees in their own department or designated department.

2. Create the following table

They are job table, department table, user job association table and role department association table

Add dept_ID to my_user; Add datA_scpoe to the my_ROLE table. The former one is very easy to understand, is the id of the department, and the latter one represents the scope of data permission of the role (this article is difficult to write, the code content of the article is also difficult to write, we want to understand thoroughly or to see from the source code, do it yourself to really understand)

Effect of three,

The effect

The effect is like this, the code is not posted, this part of the logic is a bit complex, the code is very large, you can go to the source code to view.

Four, implementation,

This is just an introduction to how to implement data permissions, referring to how to implement in the project first we define a custom annotation, okay

/** * Data permission filtering annotation *@author codermy
 * @createTime2020/8/22 * /
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermission {
    /** * Department table alias */
    public String deptAlias(a) default "";

    /**
     * 用户表的别名
     */
    public String userAlias(a) default "";
}

Copy the code

Define a section class

	/** * data filtering *@author codermy
 * @createTime2020/8/22 * /
@Aspect
@Component
public class DataScopeAspect {

    @Autowired
    public RoleUserService roleUserService;
    /** * all data permission */
    public static final String DATA_SCOPE_ALL = "1";

    /** * Custom data permission */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /** * Department data permission */
    public static final String DATA_SCOPE_DEPT = "3";

    /** ** department and the following data permissions */
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

    /** * Only my data permission */
    public static final String DATA_SCOPE_SELF = "5";

    /** * Data permission filtering keyword */
    public static final String DATA_SCOPE = "dataScope";

    /** * configures the insertion point */
    @Pointcut("@annotation(com.codermy.myspringsecurityplus.admin.annotation.DataPermission)")
    public void dataScopePointCut(a)
    {}@Before("dataScopePointCut()")
    public void doBefore(JoinPoint point) throws Throwable
    {
        handleDataScope(point);
    }

    protected void handleDataScope(final JoinPoint joinPoint)
    {
        // Get comments
        DataPermission controllerDataScope = getAnnotationLog(joinPoint);
        if (controllerDataScope == null)
        {
            return;
        }
        // Get the current user
        JwtUserDto currentUser = SecurityUtils.getCurrentUser();
        if(currentUser ! =null)
        {
            // If you are the super administrator, data is not filtered
            if(! currentUser.isAdmin()) { dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias()); }}}/** * Data range filtering **@paramJoinPoint tangent point *@paramUser *@paramDeptAlias Department alias *@paramUserAlias indicates the userAlias */
    public static void dataScopeFilter(JoinPoint joinPoint, JwtUserDto user, String deptAlias, String userAlias)
    {
        StringBuilder sqlString = new StringBuilder();

        for (MyRole role : user.getRoleInfo())
        {
            String dataScope = role.getDataScope();
            if (DATA_SCOPE_ALL.equals(dataScope))
            {
                sqlString = new StringBuilder();
                break;
            }
            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
            {
                sqlString.append(StrUtil.format(
                        " OR {}.id IN ( SELECT dept_id FROM my_role_dept WHERE role_id = {} ) ", deptAlias,
                        role.getId()));
            }
            else if (DATA_SCOPE_DEPT.equals(dataScope))
            {
                sqlString.append(StrUtil.format(" OR {}.id = {} ", deptAlias, user.getMyUser().getDeptId()));
            }
            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
            {
                sqlString.append(StrUtil.format(
                        " OR {}.id IN ( SELECT id FROM my_dept WHERE id = {} or find_in_set( {} , ancestors ) )",
                        deptAlias, user.getMyUser().getDeptId(), user.getMyUser().getDeptId()));
            }
            else if (DATA_SCOPE_SELF.equals(dataScope))
            {
                if (StrUtil.isNotBlank(userAlias))
                {
                    sqlString.append(StrUtil.format(" OR {}.id = {} ", userAlias, user.getMyUser().getId()));
                }
                else
                {
                    // Data permissions are only for myself without the userAlias alias and no data is queried
                    sqlString.append(" OR 1=0 "); }}}if (StrUtil.isNotBlank(sqlString.toString()))
        {
            BaseEntity baseEntity;
            for (int i = 0; i < joinPoint.getArgs().length ; i++ ){if (joinPoint.getArgs()[i] instanceof BaseEntity){
                    baseEntity= (BaseEntity) joinPoint.getArgs()[i];
                    baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); }}}}/** * if there are annotations, if so, get */
    private DataPermission getAnnotationLog(JoinPoint joinPoint)
    {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if(method ! =null)
        {
            return method.getAnnotation(DataPermission.class);
        }
        return null; }}Copy the code

To explain what this aspect class does: When you define this annotation on a ServiceImpl method, it takes the dataScope (or data range) of the role of the currently logged in user, compares its value, and stores the corresponding SQL statement into the baseEntity params

Then we just need to add ${params.datascope} to mapper.xml where we need to configure data permissions.Add the @dataperMission (deptAlias = “d”, userAlias = “u”) annotation to the service method that calls this methodHere I add a params property in BaseEntity to hold the SQL for data permissionsSo when we need to call this SQL, if the permissions are not filtered, the SQL looks like this

SELECT u.id, u.dept_id, u.user_name, u.password, u.nick_name
	, u.phone, u.email, u.status, u.create_time, u.update_time
FROM my_user u
	LEFT JOIN my_dept d ON u.dept_id = d.id
WHERE u.dept_id = ?
	OR u.dept_id IN (
		SELECT e.id
		FROM my_dept e
		WHEREFIND_IN_SET(? , ancestors) )ORDER BY u.id
Copy the code

If we gave this role custom data permissions, the SQL would look like this

SELECT u.id, u.dept_id, u.user_name, u.password, u.nick_name
	, u.phone, u.email, u.status, u.create_time, u.update_time
FROM my_user u
	LEFT JOIN my_dept d ON u.dept_id = d.id
WHERE (u.dept_id = ?
		OR u.dept_id IN (
			SELECT e.id
			FROM my_dept e
			WHEREFIND_IN_SET(? , ancestors) ))AND d.id IN (
		SELECT dept_id
		FROM my_role_dept
		WHERE role_id = 2
	)
ORDER BY u.id
Copy the code

So if we give the role ‘normal user’ the following data permissionsTherefore, when we log in to the user of this role, we can only access the user information of the corresponding department. This is what happens when we add annotation time filtering statements to the corresponding methods and SQL of the department giteeandgithubUpdate the source code synchronously