mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-10-09 04:57:11 +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