codingtechwork
引言
在基于 java 的开发中,通常使用 spring 框架来实现权限管理、注解和切面编程。为了实现您提到的权限控制逻辑,我们可以按照以下步骤来实现注解、切面以及权限检查。以下是一个详细的实现方案:
定义权限注解
首先,我们需要定义一个自定义的注解 @permissioncheck,这个注解会包含操作类型(crud)、资产id和资产名称作为入参。可以参考以下代码来定义这个注解:
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
// 该注解作用于方法
@target(elementtype.method)
// 运行时生效
@retention(retentionpolicy.runtime)
public @interface permissioncheck {
// 操作类型,默认为 read
string operation() default "read";
// 资产 id
string assetid() default "";
// 资产名称
string assetname() default "";
// 还可以扩展其他的字段
... ...
}在 controller 方法中使用注解
然后,在需要进行权限验证的 controller 方法中,我们可以使用 @permissioncheck 注解来指定需要的操作类型、资产 id 和资产名称。
@restcontroller
@requestmapping("/assets")
public class assetcontroller {
// 只允许读取权限
@permissioncheck(operation = "read", assetid = "asset123", assetname = "asseta")
@getmapping("/view")
public asset viewasset(@requestparam string assetid) {
// 业务逻辑
return assetservice.getassetbyid(assetid);
}
// 只允许创建操作
@permissioncheck(operation = "create", assetid = "asset124", assetname = "assetb")
@postmapping("/create")
public asset createasset(@requestbody asset asset) {
// 业务逻辑
return assetservice.createasset(asset);
}
}切面(aspect)实现权限验证
接下来,我们要创建一个切面类,利用 aop(面向切面编程)拦截标记了 @permissioncheck 注解的方法。通过切面,我们可以获取用户的角色信息,判断用户是否有权限进行特定操作,并根据需要抛出异常。
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.before;
import org.aspectj.lang.annotation.pointcut;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.security.core.context.securitycontextholder;
import org.springframework.stereotype.component;
@aspect
@component
public class permissionaspect {
// 用于获取当前用户的权限信息
@autowired
private userservice userservice;
// 切入点,拦截标注 @permissioncheck 的方法
@pointcut("@annotation(permissioncheck)")
public void checkpermission(permissioncheck permissioncheck) {}
// 在方法执行前进行权限校验
@before("checkpermission(permissioncheck)")
public void checkpermissionbefore(permissioncheck permissioncheck) throws exception {
string operation = permissioncheck.operation();
string assetid = permissioncheck.assetid();
string assetname = permissioncheck.assetname();
// 获取当前登录用户的 id
string userid = securitycontextholder.getcontext().getauthentication().getname();
// 获取当前用户的角色:可以是只读或正常用户等
user user = userservice.getuserbyid(userid);
if ("read".equals(operation) && !user.isreadonly()) {
// 如果是只读用户但操作不是 read,抛出异常
throw new permissionexception("只读用户不允许进行此操作");
}
// 检查操作权限:只允许特定用户对特定资产进行 create/update/delete 操作
if (!"read".equals(operation)) {
if (!haspermission(userid, assetid, assetname)) {
throw new permissionexception("用户没有访问该资产的权限");
}
}
}
private boolean haspermission(string userid, string assetid, string assetname) {
// 查询数据库,检查当前用户是否对给定的资产 id 或资产名称有权限
return userservice.hasassetpermission(userid, assetid, assetname);
}
}4. 用户权限服务实现
在上面的切面代码中,我们调用了 userservice 来判断当前用户是否有权限操作某个资产。userservice 需要实现以下逻辑:
@service
public class userservice {
// 根据用户 id 查询用户信息,判断是否为只读用户
public user getuserbyid(string userid) {
// 假设从数据库获取用户信息
return userrepository.findbyid(userid).orelsethrow(() -> new usernotfoundexception("用户不存在"));
}
// 查询用户是否有访问某个资产的权限
public boolean hasassetpermission(string userid, string assetid, string assetname) {
// 这里我们可以查询数据库,检查当前用户是否有对应资产的权限
return permissionrepository.existsbyuseridandassetidorassetname(userid, assetid, assetname);
}
}异常处理
当权限不满足时,我们需要抛出自定义的异常并进行全局处理。
public class permissionexception extends runtimeexception {
public permissionexception(string message) {
super(message);
}
}
@controlleradvice
public class globalexceptionhandler {
@exceptionhandler(permissionexception.class)
@responsestatus(httpstatus.forbidden)
public responseentity<string> handlepermissionexception(permissionexception ex) {
return responseentity.status(httpstatus.forbidden).body(ex.getmessage());
}
}其他相关注意事项
- 只读用户的限制:在
checkpermissionbefore方法中,我们通过判断operation字段来确定是否是只读用户操作。若是只读用户,但操作尝试修改数据(create/update/delete),则会抛出异常。 - 权限查询优化:在实际项目中,查询数据库是否有权限时,可以使用缓存来提高查询性能,避免频繁的数据库访问。
- 全局异常处理:通过
@controlleradvice和自定义异常类,能够确保权限错误的响应更加友好和统一。
总结
通过以上的实现,我们使用了自定义注解、切面编程和用户权限服务的组合来对方法进行权限控制,确保只读用户无法进行修改操作,同时判断其他用户是否有权限访问特定的资产。这样的方法可以灵活扩展,方便在大型系统中进行细粒度的权限控制。
到此这篇关于springboot越权和数据权限控制的实现方案(最新整理)的文章就介绍到这了,更多相关springboot 权限控制内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论