Knowledge sharing: do you know the role authorization and authentication of rights management?

Time:2021-6-11

In authority management, role authorization and authentication belong to the key module of authority module. Role authorization is the act of assigning menu resources that a role can operate to a specified role. Role authentication is the operation of verifying the permissions of user operated resources after a user plays a specified role and logs into the system, So how to implement it in code?

The way of role authorization and authentication

Case practice

Role authorization

Tree data display

After completing the basic crud function of role record, the next step is to realize the role authorization function. Here, to realize the role authorization, the first step is to complete the display function of resources to be authorized. For the display of resources, the open source tree plug-in is used hereztree

Back end implementation of resource data query

Resource data format reference displayed by front end ztreehere

  • 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 authorization 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 the role record to be authorized!”{ icon: 5});
return;
}
if(datas.length>1){
Layer.msg (“batch role authorization is not supported at the moment!”{ icon: 5});
return;
}
var url  =  ctx+”/role/toAddGrantPage?roleId=”+datas[0].id;
var;
layui.layer.open({
title : title,
type : 2,
area:[“600px”,”280px”],
maxmin:true,
content : url
});
}

  • Rolecontroller.java add view forwarding method

@RequestMapping(“toAddGrantPage”)
public String toAddGrantPage(Integer roleId,Model model){
model.addAttribute(“roleId”,roleId);
return “role/grant”;
}

  • Ready to display resource data template

Add grant.ftl template file in 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”></script>
<script type=”text/javascript”></script>
<script type=”text/javascript”></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”></script>
</body>
</html>

  • Add grant.js

var zTreeObj;
$(function () {
loadModuleInfo();
});
function loadModuleInfo() {
$.ajax({
type:”post”,
url:ctx+”/module/queryAllModules”
dataType:”json”,
success:function (data) {
//For the parameter configuration of ztree, please refer to the API document (setting configuration details) for further use
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

Back end implementation of adding permission records
  • RoleService.java

public void addGrant(Integer[] mids, Integer roleId) {
/**

  • Core table-t_ permission t_ Role (verify role exists)
  • If the role has original permissions, delete the original permissions of the role
  • Then add new permissions of roles and batch add permission 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 allocation 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 front end core JS to permission record

Modify the grant.js file, add the ztree check box, and click callback onCheck event.

var zTreeObj;
$(function () {
loadModuleInfo();
});
function loadModuleInfo() {
$.ajax({
type:”post”,
url:ctx+”/module/queryAllModules”,
dataType:”json”,
success:function (data) {
//For the parameter configuration of ztree, please refer to the API document (setting configuration details) for further use
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);
}
})
}

Role added permission record echo

Here, to realize the function of displaying the original permissions when the added role record permissions are viewed or authorized again, whether to select attribute configuration reference in ztree check boxhere

Implementation of resource query back end method
  • ModuleService.java

public List<TreeDto> queryAllModules02(Integer roleId) {
List<TreeDto> treeDtos=moduleMapper.queryAllModules();
//Query the menu ID list < integer > owned by the role according to the role ID
List<Integer> roleHasMids=permissionMapper.queryRoleHasAllModuleIdsByRoleId(roleId);
if(null !=roleHasMids && roleHasMids.size()>0){
treeDtos.forEach(treeDto -> {
if(roleHasMids.contains(treeDto.getId())){
//Indicates that the menu is assigned to the current role
treeDto.setChecked(true);
}
});
}
return  treeDtos;
}

  • Role has permission to query SQL

<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 you modify grant.js to query resources, you pass in the current selected role ID

function loadModuleInfo() {
$.ajax({
type:”post”,
url:ctx+”/module/queryAllModules”,
data:{
roleId:$(“#roleId”).val()
},
dataType:”json”,
success:function (data) {
//For the parameter configuration of ztree, please refer to the API document (setting configuration details) for further use
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 the function of adding role permissions is completed, the next step is to authenticate the resources of role operations. Here, authentication includes two parts:

  1. Menu level display control
  2. Back end method access control

Implementation of menu level access control

According to the different roles played by the login user, the system dynamically controls and displays the menu operated by the login user, and the control displayed here is usedfreemarkerInstruction + built-in function implementation, instruction and built-in function operation referencehere

Login user role has the right to query
  • IndexController.java

/**

  • Back end 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 part of the menu control is shown here.

<#if permissions?seq_contains(“60”)>
<li class=”layui-nav-item”>
< span class = “layui left nav” > system settings < / span > < span class = “layui NAV more” ></span>
<dl class=”layui-nav-child”>
<#if permissions?seq_contains(“6010”)>
<dd>
< span class = “layui left nav” > User Management</span>
</dd>
</#if>
<#if permissions?seq_contains(“6020”)>
<dd class=””>
< span class = “layui left nav” > role management</span>
</dd>
</#if>
<#if permissions?seq_contains(“6030”)>
<dd class=””>
< span class = “layui left nav” > menu management</span>
</dd>
</#if>
</dl>
</li>
</#if>

Back end method level access control

The menu level display control is implemented, but the client may enter the resource address through the browser to cross the UI interface to access the back-end resources. So next, the access control operation of control method level resources is added, which is implemented by AOP + custom annotation

Custom annotation @ requirepermission

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequirePermission {
String code() default “”;
}

Method level use annotations

@RequestMapping(“list”)
@ResponseBody
@RequirePermission(code = “101001”)
public Map<String,Object> querySaleChancesByParams(Integer flag,HttpServletRequest request,SaleChanceQuery saleChanceQuery){
if(null !=flag &&flag==1){
//Query the marketing records assigned to the current login user
saleChanceQuery.setAggsinMan(LoginUserUtil.releaseUserIdFromCookie(request));
}
return  saleChanceService.queryByParamsForTable(saleChanceQuery);
}

Defining AOP facet class to intercept specified 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 adds support for metadata, that is, annotations. Annotations are different from annotations. Annotations can be understood as special tags in code. These tags can be read and processed during compilation, class loading and runtime. Through annotation, 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 a 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 for annotations, which are responsible for the properties of custom annotations

*/
@Target({ElementType.TYPE,ElementType.METHOD})    // Represents the action object of annotation, elementtype.type represents class, and elementtype.method represents method
@Retention(RetentionPolicy.RUNTIME)        // Represents the retention mechanism of annotations, and retentionpolicy. Runtime represents runtime annotations
@Inherited            // Indicates that the annotation is inheritable
@Documented            // Indicates that the annotation can generate a document
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
}

Using annotations

package com.lebyte;

import com.lebyte.annotations.Design;

@Design(author=”lebyte”,data=100)    // Using custom annotation, members with default values need not be assigned values, and other members need to be assigned values
public class Person {
@Design(author=”lebyte”,data=90)
public void live(){

}
}

Parsing 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 whether a class is assigned an annotation
Design d=(Design) c.getAnnotation(Design.class);    // Gets the specified annotation instance on the class
System.out.println(d.data());
}

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

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

}