Do you know the role authorization and authentication of rights management?

In rights management, role authorization and authentication belong to the key modules in the rights module. Role authorization is the act of assigning the menu resources that the role can operate to the designated role. The role authentication is instant when the user plays the designated role and logs in to the system. The operation of resource permission verification is explained here, so how should it be implemented in the code?

Role authorization and authentication methods

  • Front-end page display control
  • Back-end permission access control

The most complete java learning materials→q 1080355292 (group password: 1010)

Case practice

role authorization

tree data display

After completing the basic crud function of the role record, the role authorization function is implemented next. Here, the role authorization is implemented first to complete the display function of the resources to be authorized. For the display of resources, the open source tree plugin is used here ztree.

Resource data query backend implementation

The resource data format reference displayed by the front-end ztree here.

  • ModuleMapper.xml
<select id="queryAllModules" resultType="com.xxxx.crm.dto.TreeDto">
    select
    id,
    IFNULL(parent_id,0) as pId,
    module_name AS name
    from t_module
    where is_valid=1
</select>
  • ModuleService.java
public List<TreeDto> queryAllModules(){
    return moduleMapper.queryAllModules();
}
  • ModuleController.java
@RequestMapping("queryAllModules")
@ResponseBody
public List<TreeDto> queryAllModules(){
    return moduleService.queryAllModules();
}
Resource data ztree display
  • role.js add authorized click event
//header toolbar events
table.on('toolbar(roles)', function(obj){
    var checkStatus = table.checkStatus(obj.config.id);
    switch(obj.event){
        case "add":
            openAddOrUpdateRoleDialog();
            break;
        case "grant":
            openAddGrantDailog(checkStatus.data);
            break;
    };
});

function openAddGrantDailog(datas){
    if(datas.length==0){
        layer.msg("Please select a role record to be authorized!", {icon: 5});
        return;
    }
    if(datas.length>1){
        layer.msg("Batch role authorization is not currently supported!", {icon: 5});
        return;
    }
    var url  =  ctx+"/role/toAddGrantPage?roleId="+datas[0].id;
    var title="role management-role authorization";
    layui.layer.open({
        title : title,
        type : 2,
        area:["600px","280px"],
        maxmin:true,
        content : url
    });
}
  • RoleController.java adds view forwarding method
@RequestMapping("toAddGrantPage")
public String toAddGrantPage(Integer roleId,Model model){
    model.addAttribute("roleId",roleId);
    return "role/grant";
}
  • Prepare to display resource data template

Add the grant.ftl template file to the views/role directory

<html>
<head>
   <link rel="stylesheet" href="${ctx}/static/js/zTree_v3-3.5.32/css/zTreeStyle/zTreeStyle.css" type="text/css">
   <script type="text/javascript" src="${ctx}/static/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script>
   <script type="text/javascript" src="${ctx}/static/js/zTree_v3-3.5.32/js/jquery.ztree.core.js"></script>
   <script type="text/javascript" src="${ctx}/static/js/zTree_v3-3.5.32/js/jquery.ztree.excheck.js"></script>
</head>
<body>
<div id="test1" class="ztree"></div>
<input id="roleId" value="${roleId!}" type="hidden">
<script type="text/javascript">
   var ctx="${ctx}";
</script>
<script type="text/javascript" src="${ctx}/static/js/role/grant.js"></script>
</body>
</html>
  • add grant.js
var zTreeObj;
$(function () {
    loadModuleInfo();
});
function loadModuleInfo() {
    $.ajax({
        type:"post",
        url:ctx+"/module/queryAllModules"
        dataType:"json",
        success:function (data) {
            // Parameter configuration of zTree, please refer to the API documentation for in-depth use (detailed explanation of setting configuration)
            var setting = {
                data: {
                    simpleData: {
                        enable: true
                    }
                },
                view:{
                    showLine: false
                    // showIcon: false
                },
                check: {
                    enable: true,
                    chkboxType: { "Y": "ps", "N": "ps" }
                }
            };
            var zNodes =data;
            zTreeObj=$.fn.zTree.init($("#test1"), setting, zNodes);
        }
    })
}

role authorization

Permission record add backend implementation
  • RoleService.java
public void addGrant(Integer[] mids, Integer roleId) {
        /**
         * Core table - t_permission t_role (verify that the role exists)
         *   If the role has original permissions, delete the original permissions of the role
         *     Then add new permissions for roles and batch add permissions records to t_permission
         */
        Role temp =selectByPrimaryKey(roleId);
        AssertUtil.isTrue(null==roleId||null==temp,"The role to be authorized does not exist!");
        int count = permissionMapper.countPermissionByRoleId(roleId);
        if(count>0){
            AssertUtil.isTrue(permissionMapper.deletePermissionsByRoleId(roleId)<count,"Permission assignment failed!");
        }
        if(null !=mids && mids.length>0){
            List<Permission> permissions=new ArrayList<Permission>();
            for (Integer mid : mids) {
                Permission permission=new Permission();
                permission.setCreateDate(new Date());
                permission.setUpdateDate(new Date());
                permission.setModuleId(mid);
                permission.setRoleId(roleId);
                permission.setAclValue(moduleMapper.selectByPrimaryKey(mid).getOptValue());
                permissions.add(permission);
            }
            permissionMapper.insertBatch(permissions);
        }
}
  • RoleController.java
@RequestMapping("addGrant")
@ResponseBody
public ResultInfo addGrant(Integer[] mids,Integer roleId){
    roleService.addGrant(mids,roleId);
    return success("Permission added successfully");
}
Add the front-end core js to the permission record

Modify grant.js file to add ztree checkbox click callback onCheck event.

var zTreeObj;
$(function () {
    loadModuleInfo();
});
function loadModuleInfo() {
    $.ajax({
        type:"post",
        url:ctx+"/module/queryAllModules",
        dataType:"json",
        success:function (data) {
            // Parameter configuration of zTree, please refer to the API documentation for in-depth use (detailed explanation of setting configuration)
            var setting = {
                data: {
                    simpleData: {
                        enable: true
                    }
                },
                view:{
                    showLine: false
                    // showIcon: false
                },
                check: {
                    enable: true,
                    chkboxType: { "Y": "ps", "N": "ps" }
                },
                callback: {
                    onCheck: zTreeOnCheck
                }
            };
            var zNodes =data;
            zTreeObj=$.fn.zTree.init($("#test1"), setting, zNodes);
        }
    })
}

function zTreeOnCheck(event, treeId, treeNode) {
    var nodes= zTreeObj.getCheckedNodes(true);
        var roleId=$("#roleId").val();
        var mids="mids=";
        for(var i=0;i<nodes.length;i++){
            if(i<nodes.length-1){
                mids=mids+nodes[i].id+"&mids=";
            }else{
                mids=mids+nodes[i].id;
            }
        }
    $.ajax({
            type:"post",
            url:ctx+"/role/addGrant",
            data:mids+"&roleId="+roleId,
            dataType:"json",
            success:function (data) {
                console.log(data);
            }
    })
}
The role has been added permission record echo

Here to realize the function of displaying the original permissions when viewing or authorizing the added role record permissions again, check whether the ztree checkbox selects the attribute configuration reference here.

Resource query backend method implementation
  • ModuleService.java
public List<TreeDto> queryAllModules02(Integer roleId) {
    List<TreeDto> treeDtos=moduleMapper.queryAllModules();
    // Query the menu id list<integer>
    List<Integer> roleHasMids=permissionMapper.queryRoleHasAllModuleIdsByRoleId(roleId);
    if(null !=roleHasMids && roleHasMids.size()>0){
        treeDtos.forEach(treeDto -> {
            if(roleHasMids.contains(treeDto.getId())){
                //  Indicates that the current role is assigned to this menu
                treeDto.setChecked(true);
            }
        });
    }
    return  treeDtos;
}
  • role has permission sql query
<select id="queryRoleHasAllModuleIdsByRoleId" parameterType="int" resultType="java.lang.Integer">
    select module_id from t_permission where role_id=#{roleId}
</select>
  • ModuleController.java
@RequestMapping("queryAllModules")
@ResponseBody
public List<TreeDto> queryAllModules(Integer roleId){
    return moduleService.queryAllModules02(roleId);
}
Permission echo front-end js

Here, when modifying grant.js to query resources, pass in the id of the currently selected role

function loadModuleInfo() {
    $.ajax({
        type:"post",
        url:ctx+"/module/queryAllModules",
        data:{
            roleId:$("#roleId").val()
        },
        dataType:"json",
        success:function (data) {
            // Parameter configuration of zTree, please refer to the API documentation for in-depth use (detailed explanation of setting configuration)
            var setting = {
                data: {
                    simpleData: {
                        enable: true
                    }
                },
                view:{
                    showLine: false
                    // showIcon: false
                },
                check: {
                    enable: true,
                    chkboxType: { "Y": "ps", "N": "ps" }
                },
                callback: {
                    onCheck: zTreeOnCheck
                }
            };
            var zNodes =data;
            zTreeObj=$.fn.zTree.init($("#test1"), setting, zNodes);
        }
    })
}

role authentication

After completing the function of adding role permissions, the next step is to authenticate the resources operated by the role. There are two pieces of authentication here:

  1. Menu level display controls
  2. Backend method access control

Menu level access control implementation

The system dynamically controls and displays the menu operated by the logged-in user according to the different roles played by the logged-in user. The control displayed here uses freemarker Instruction + built-in function implementation, instruction and built-in function operation reference here.

Login user role has permission query implementation
  • IndexController.java
/**
 * Backend management main page
 * @return
 */
@RequestMapping("main")
public String main(HttpServletRequest request){
    Integer userId = LoginUserUtil.releaseUserIdFromCookie(request);
    request.setAttribute("user",userService.selectByPrimaryKey(userId));
    List<String> permissions=permissionService.queryUserHasRolesHasPermissions(userId);
    request.getSession().setAttribute("permissions",permissions);
    return "main";
}
  • PermissionService.java
@Service
public class PermissionService extends BaseService<Permission,Integer> {

    @Autowired
    private PermissionMapper permissionMapper;

    public List<String> queryUserHasRolesHasPermissions(Integer userId) {
        return permissionMapper.queryUserHasRolesHasPermissions(userId);
    }
}
  • PermissionMapper.java & PermissionMapper.xml
public interface PermissionMapper extends BaseMapper<Permission,Integer> {
    List<String>  queryUserHasRolesHasPermissions(Integer userId);
}
<select id="queryUserHasRolesHasPermissions" parameterType="int" resultType="java.lang.String">
    select distinct p.acl_value
    from t_user_role ur left join  t_permission p on ur.role_id = p.role_id
    where ur.user_id=#{userId}
</select>
System main page menu display command control

Only some of the menu controls are shown here.

<#if permissions?seq_contains("60")>
    <li class="layui-nav-item">
        <a href="javascript:;" class="layui-menu-tips"><i class="fa fa-gears"></i><span class="layui-left-nav"> system settings</span> <span class="layui-nav-more"></span></a>
        <dl class="layui-nav-child">
            <#if permissions?seq_contains("6010")>
                <dd>
                    <a href="javascript:;" class="layui-menu-tips" data-type="tabAdd" data-tab-mpi="m-p-i-11" data-tab="user/index" target="_self"><i class="fa fa-user"></i><span class="layui-left-nav"> User Management</span></a>
                </dd>
                </#if>
            <#if permissions?seq_contains("6020")>
                <dd class="">
                    <a href="javascript:;" class="layui-menu-tips" data-type="tabAdd" data-tab-mpi="m-p-i-12" data-tab="role/index" target="_self"><i class="fa fa-tachometer"></i><span class="layui-left-nav"> role management</span></a>
                </dd>
                </#if>
            <#if permissions?seq_contains("6030")>
                <dd class="">
                    <a href="javascript:;" class="layui-menu-tips" data-type="tabAdd" data-tab-mpi="m-p-i-13" data-tab="module/index" target="_self"><i class="fa fa-tachometer"></i><span class="layui-left-nav"> menu management</span></a>
                </dd>
            </#if>
        </dl>
    </li>
</#if>

Backend method level access control

Accomplish provides menu level display control, but eventually the client may enter the resource address through the browser to access the back-end resources across the ui interface, so the next step is to add the control method level resource access control operation. Here, aop+ custom annotation accomplish is used

Custom annotation @RequirePermission
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequirePermission {
    String code() default "";
}
Using annotations at the method level
@RequestMapping("list")
@ResponseBody
@RequirePermission(code = "101001")
public Map<String,Object> querySaleChancesByParams(Integer flag,HttpServletRequest request,SaleChanceQuery saleChanceQuery){
    if(null !=flag &&flag==1){
        // Query marketing records assigned to the currently logged in user
        saleChanceQuery.setAggsinMan(LoginUserUtil.releaseUserIdFromCookie(request));
    }
    return  saleChanceService.queryByParamsForTable(saleChanceQuery);
}
Define the method of aop aspect class to intercept the specified annotation annotation
@Component
@Aspect
public class PermissionProxy {

    @Autowired
    private HttpSession session;

    @Around(value = "@annotation(com.xxx.sys.annotaions.RequirePermission)")
    public  Object around(ProceedingJoinPoint pjp) throws Throwable {
        List<String> permissions = (List<String>) session.getAttribute("permissions");
        if(null == permissions || permissions.size()==0){
            throw  new NoPermissionException();
        }
        Object result =null;
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        RequirePermission requirePermission = methodSignature.getMethod().getDeclaredAnnotation(RequirePermission.class);
        if(!(permissions.contains(requirePermission.code()))){
            throw  new NoPermissionException();
        }
        result= pjp.proceed();
        return result;
    }
}

extension ~ custom annotation instance

Starting from JDK5, Java has added support for metadata, that is, annotations. Annotations are different from annotations. Annotations can be understood as special tags in the code. These tags can be read during compilation, class loading, runtime, and perform the corresponding processing By annotating developers can embed supplementary information in the source code without changing the original code and logic. Let's take a look at how to customize annotations.

Create custom annotation class

package com.lebyte.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*    @Target,@Retention,@Inherited,@Documented
 *     These four are meta-annotations that annotate annotations, responsible for the attributes of custom annotations
 */
@Target({ElementType.TYPE,ElementType.METHOD})    //Represents the role object of the annotation, ElementType.TYPE represents the class, and ElementType.METHOD represents the method
@Retention(RetentionPolicy.RUNTIME)        //Represents the retention mechanism of annotations, RetentionPolicy.RUNTIME represents runtime annotations
@Inherited            //Indicates that the annotation is inheritable
@Documented            //Indicates that the annotation can generate documentation
public @interface Design {
    String author();        //Annotation member, if the annotation has only one member, the member name must be value(), and the member type can only be the original type
    int data() default 0;    //Annotation member, the default value is 0
}

use annotations

package com.lebyte;

import com.lebyte.annotations.Design;

@Design(author="lebyte",data=100)    //Using custom annotations, members with default values ​​do not need to be assigned, and the rest of the members must be assigned
public class Person {
    @Design(author="lebyte",data=90)
    public void live(){

    }
}

Parse annotations

package com.lebyte;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import com.lebyte.annotations.Design;

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {

        Class c=Class.forName("com.lebyte.Person");        //Loading classes using class loader

        //1. Find the annotation on the class
        if(c.isAnnotationPresent(Design.class)){    //Determine if the class is annotated with the specified annotation
            Design d=(Design) c.getAnnotation(Design.class);    //Get the specified annotation instance on the class
            System.out.println(d.data());
        }

        //2. Find the annotations on the method
        Method[] ms=c.getMethods();
        for(Method m:ms){
            if(m.isAnnotationPresent(Design.class)){    //Determines whether the method is annotated with the specified annotation
                Design d=m.getAnnotation(Design.class);        //Get the specified annotation instance on the class
                System.out.println(d.data());
            }
        }

        //3. Another method
        for(Method m:ms){
            Annotation[] as=m.getAnnotations();        //Get the annotation collection on the class
            for(Annotation a:as){
                if(a instanceof Design){        //Determine the specified annotation
                    Design d=(Design) a;
                    System.out.println(d.data());
                }
            }
        }
    }

}

Tags: Java Back-end

Posted by jswinkelman on Thu, 30 Jun 2022 17:55:02 +0530