mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-11-04 09:01:37 +08:00 
			
		
		
		
	新增:新增功能权限适配及校验
1.后端 API 注解鉴权使用方式:@SaCheckPermission("system:user:add")
2.前端全局指令函数使用方式:v-permission="['system:user:add']"
3.前端权限判断函数使用方式:checkPermission(['system:user:add'])
			
			
This commit is contained in:
		@@ -30,8 +30,11 @@ import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.stp.StpUtil;
 | 
			
		||||
import cn.hutool.core.lang.tree.Tree;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
 | 
			
		||||
import top.charles7c.cnadmin.common.annotation.CrudRequestMapping;
 | 
			
		||||
import top.charles7c.cnadmin.common.model.query.PageQuery;
 | 
			
		||||
import top.charles7c.cnadmin.common.model.query.SortQuery;
 | 
			
		||||
import top.charles7c.cnadmin.common.model.vo.PageDataVO;
 | 
			
		||||
@@ -72,6 +75,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @GetMapping
 | 
			
		||||
    protected R<PageDataVO<V>> page(@Validated Q query, @Validated PageQuery pageQuery) {
 | 
			
		||||
        this.checkPermission("list");
 | 
			
		||||
        PageDataVO<V> pageDataVO = baseService.page(query, pageQuery);
 | 
			
		||||
        return R.ok(pageDataVO);
 | 
			
		||||
    }
 | 
			
		||||
@@ -89,6 +93,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @GetMapping("/tree")
 | 
			
		||||
    protected R<List<Tree<Long>>> tree(@Validated Q query, @Validated SortQuery sortQuery) {
 | 
			
		||||
        this.checkPermission("list");
 | 
			
		||||
        List<Tree<Long>> list = baseService.tree(query, sortQuery, false);
 | 
			
		||||
        return R.ok(list);
 | 
			
		||||
    }
 | 
			
		||||
@@ -106,6 +111,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    protected R<List<V>> list(@Validated Q query, @Validated SortQuery sortQuery) {
 | 
			
		||||
        this.checkPermission("list");
 | 
			
		||||
        List<V> list = baseService.list(query, sortQuery);
 | 
			
		||||
        return R.ok(list);
 | 
			
		||||
    }
 | 
			
		||||
@@ -122,6 +128,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    protected R<D> get(@PathVariable Long id) {
 | 
			
		||||
        this.checkPermission("list");
 | 
			
		||||
        D detail = baseService.get(id);
 | 
			
		||||
        return R.ok(detail);
 | 
			
		||||
    }
 | 
			
		||||
@@ -137,6 +144,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @PostMapping
 | 
			
		||||
    protected R<Long> add(@Validated(BaseRequest.Add.class) @RequestBody C request) {
 | 
			
		||||
        this.checkPermission("add");
 | 
			
		||||
        Long id = baseService.add(request);
 | 
			
		||||
        return R.ok("新增成功", id);
 | 
			
		||||
    }
 | 
			
		||||
@@ -152,6 +160,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @PutMapping
 | 
			
		||||
    protected R update(@Validated(BaseRequest.Update.class) @RequestBody C request) {
 | 
			
		||||
        this.checkPermission("update");
 | 
			
		||||
        baseService.update(request);
 | 
			
		||||
        return R.ok("修改成功");
 | 
			
		||||
    }
 | 
			
		||||
@@ -168,6 +177,7 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    @DeleteMapping("/{ids}")
 | 
			
		||||
    protected R delete(@PathVariable List<Long> ids) {
 | 
			
		||||
        this.checkPermission("delete");
 | 
			
		||||
        baseService.delete(ids);
 | 
			
		||||
        return R.ok("删除成功");
 | 
			
		||||
    }
 | 
			
		||||
@@ -185,6 +195,20 @@ public abstract class BaseController<S extends BaseService<V, D, Q, C>, V, D, Q,
 | 
			
		||||
    @Operation(summary = "导出数据")
 | 
			
		||||
    @GetMapping("/export")
 | 
			
		||||
    protected void export(@Validated Q query, @Validated SortQuery sortQuery, HttpServletResponse response) {
 | 
			
		||||
        this.checkPermission("export");
 | 
			
		||||
        baseService.export(query, sortQuery, response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 权限认证
 | 
			
		||||
     *
 | 
			
		||||
     * @param subPermission
 | 
			
		||||
     *            部分权限码
 | 
			
		||||
     */
 | 
			
		||||
    private void checkPermission(String subPermission) {
 | 
			
		||||
        CrudRequestMapping crudRequestMapping = this.getClass().getDeclaredAnnotation(CrudRequestMapping.class);
 | 
			
		||||
        String path = crudRequestMapping.value();
 | 
			
		||||
        String permissionPrefix = String.join(":", StrUtil.splitTrim(path, "/"));
 | 
			
		||||
        StpUtil.checkPermission(String.format("%s:%s", permissionPrefix, subPermission));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@ import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.bean.BeanUtil;
 | 
			
		||||
import cn.hutool.core.bean.copier.CopyOptions;
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.convert.Convert;
 | 
			
		||||
import cn.hutool.core.lang.Opt;
 | 
			
		||||
@@ -165,7 +166,10 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T, V, D, Q, C ext
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public void update(C request) {
 | 
			
		||||
        T entity = BeanUtil.copyProperties(request, entityClass);
 | 
			
		||||
        String idName = this.currentEntityIdName();
 | 
			
		||||
        Object idValue = ReflectUtil.getFieldValue(request, idName);
 | 
			
		||||
        T entity = this.getById(idValue);
 | 
			
		||||
        BeanUtil.copyProperties(request, entity, CopyOptions.create().ignoreNullValue());
 | 
			
		||||
        baseMapper.updateById(entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -211,8 +215,8 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T, V, D, Q, C ext
 | 
			
		||||
     *            ID
 | 
			
		||||
     * @return 实体信息
 | 
			
		||||
     */
 | 
			
		||||
    protected T getById(Long id) {
 | 
			
		||||
        T entity = baseMapper.selectById(id);
 | 
			
		||||
    protected T getById(Object id) {
 | 
			
		||||
        T entity = baseMapper.selectById(Convert.toStr(id));
 | 
			
		||||
        CheckUtils.throwIfNull(entity, String.format("ID为 [%s] 的记录已不存在", id));
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,12 @@ public class Constants {
 | 
			
		||||
    /**
 | 
			
		||||
     * 超级管理员角色编码
 | 
			
		||||
     */
 | 
			
		||||
    public static final String ADMIN_ROLE_CODE = "admin";
 | 
			
		||||
    public static final String SUPER_ADMIN = "admin";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 全部权限标识
 | 
			
		||||
     */
 | 
			
		||||
    public static final String ALL_PERMISSION = "*";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 默认密码
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,8 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
 | 
			
		||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.exception.NotLoginException;
 | 
			
		||||
import cn.dev33.satoken.exception.NotPermissionException;
 | 
			
		||||
import cn.dev33.satoken.exception.NotRoleException;
 | 
			
		||||
import cn.hutool.core.util.NumberUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
 | 
			
		||||
@@ -163,7 +165,20 @@ public class GlobalExceptionHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 拦截认证异常-未登录异常
 | 
			
		||||
     * 拦截文件上传异常-超过上传大小限制
 | 
			
		||||
     */
 | 
			
		||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
			
		||||
    @ExceptionHandler(MaxUploadSizeExceededException.class)
 | 
			
		||||
    public R handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e, HttpServletRequest request) {
 | 
			
		||||
        log.error("请求地址'{}',上传文件失败,文件大小超过限制", request.getRequestURI(), e);
 | 
			
		||||
        String sizeLimit = StrUtil.subBetween(e.getMessage(), "The maximum size ", " for");
 | 
			
		||||
        String errorMsg = String.format("请上传小于 %s MB 的文件", NumberUtil.parseLong(sizeLimit) / 1024 / 1024);
 | 
			
		||||
        LogContextHolder.setErrorMsg(errorMsg);
 | 
			
		||||
        return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 认证异常-登录认证
 | 
			
		||||
     */
 | 
			
		||||
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
 | 
			
		||||
    @ExceptionHandler(NotLoginException.class)
 | 
			
		||||
@@ -188,15 +203,22 @@ public class GlobalExceptionHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 拦截文件上传异常-超过上传大小限制
 | 
			
		||||
     * 认证异常-权限认证
 | 
			
		||||
     */
 | 
			
		||||
    @ResponseStatus(HttpStatus.BAD_REQUEST)
 | 
			
		||||
    @ExceptionHandler(MaxUploadSizeExceededException.class)
 | 
			
		||||
    public R handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e, HttpServletRequest request) {
 | 
			
		||||
        log.error("请求地址'{}',上传文件失败,文件大小超过限制", request.getRequestURI(), e);
 | 
			
		||||
        String sizeLimit = StrUtil.subBetween(e.getMessage(), "The maximum size ", " for");
 | 
			
		||||
        String errorMsg = String.format("请上传小于 %s MB 的文件", NumberUtil.parseLong(sizeLimit) / 1024 / 1024);
 | 
			
		||||
        LogContextHolder.setErrorMsg(errorMsg);
 | 
			
		||||
        return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg);
 | 
			
		||||
    @ResponseStatus(HttpStatus.FORBIDDEN)
 | 
			
		||||
    @ExceptionHandler(NotPermissionException.class)
 | 
			
		||||
    public R handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
 | 
			
		||||
        log.error("请求地址'{}',权限码校验失败'{}'", request.getRequestURI(), e);
 | 
			
		||||
        return R.fail(HttpStatus.FORBIDDEN.value(), "没有访问权限,请联系管理员授权");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 认证异常-角色认证
 | 
			
		||||
     */
 | 
			
		||||
    @ResponseStatus(HttpStatus.FORBIDDEN)
 | 
			
		||||
    @ExceptionHandler(NotRoleException.class)
 | 
			
		||||
    public R handleNotRoleException(NotRoleException e, HttpServletRequest request) {
 | 
			
		||||
        log.error("请求地址'{}',角色权限校验失败'{}'", request.getRequestURI(), e);
 | 
			
		||||
        return R.fail(HttpStatus.FORBIDDEN.value(), "没有访问权限,请联系管理员授权");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -18,6 +18,7 @@ package top.charles7c.cnadmin.common.model.dto;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
@@ -118,4 +119,14 @@ public class LoginUser implements Serializable {
 | 
			
		||||
     * 登录时间
 | 
			
		||||
     */
 | 
			
		||||
    private LocalDateTime loginTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 权限码集合
 | 
			
		||||
     */
 | 
			
		||||
    private Set<String> permissions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 角色编码集合
 | 
			
		||||
     */
 | 
			
		||||
    private Set<String> roles;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user