如何基于SpringSecurity的@PreAuthorize实现自定义权限校验方法

下面是详细攻略。

1. SpringSecurity基本概念

SpringSecurity是基于Spring框架的安全认证和授权模块,可以为我们的应用提供强大的安全管理。在SpringSecurity中,每个用户都有一个唯一的用户名和一个密码,SpringSecurity会在用户登录时对这些信息进行校验,如果校验通过则允许用户进行下一步操作,否则拒绝用户进行任何的操作。在SpringSecurity中,要进行权限的校验,需要有一个认证和授权的机制,SpringSecurity会将其封装成一个安全上下文,使用该上下文实现用户身份认证和授权。

2. 自定义权限校验方法

在SpringSecurity中,@PreAuthorize注解是进行权限校验的主要方式之一,它可以用于Controller层的每个方法。@PreAuthorize是一种基于Expression的权限校验机制,可以借助Spring Security传递的SecurityContext进行权限校验。

下面是一些常用的Expression:

  • hasRole: 判断用户是否具有角色,比如ROLE_ADMIN
  • hasAuthority: 判断用户是否有权限,比如EDIT
  • hasIpAddress: 判断用户是否来自指定的IP地址
  • hasPermission: 判断用户是否有指定的权限

我们可以通过在Controller上加上@PreAuthorize注解,并在注解中指定Expression来实现权限校验。

下面是一个示例:

@RestController
@RequestMapping("/api/v1")
public class UserController {

    @GetMapping("/user/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<User> findById(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
}

在上面的示例中,@PreAuthorize注解中的Expression是"hasRole('ADMIN')",表示只有具有ADMIN角色的用户才能访问该接口。

但是,上述示例中的Expression是写死的,如果我们需要根据不同的业务需求来动态判断用户的访问权限,就需要自定义权限校验方法。下面是自定义权限校验方法的步骤:

  1. 创建一个自定义的PermissionEvaluator实现类,实现hasPermission()方法,并注入到Spring容器中。hasPermission()方法的第一个参数代表SecurityContext,第二个参数代表当前的Object对象,第三个参数代表权限字符串。
@Component
public class MyPermissionEvaluator implements PermissionEvaluator {

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if (authentication == null || !permission.equals("edit")) {
            return false;
        }

        User user = (User) authentication.getPrincipal();
        Long userId = user.getId();

        if (targetDomainObject instanceof User) {
            return ((User) targetDomainObject).getId().equals(userId);
        } else if (targetDomainObject instanceof Comment) {
            Comment comment = (Comment) targetDomainObject;
            return comment.getUserId().equals(userId);
        } else {
            return false;
        }
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        throw new UnsupportedOperationException();
    }
}
  1. 在Controller上使用@PreAuthorize注解,指定自定义的权限校验方法,使用"#target"代表需要校验的对象。
@RestController
@RequestMapping("/api/v1")
public class UserController {

    @GetMapping("/user/{id}")
    @PreAuthorize("@myPermissionEvaluator.hasPermission(authentication, #user, 'edit')")
    public ResponseEntity<User> findById(@PathVariable("id") User user) {
        return ResponseEntity.ok(user);
    }
}

在上面的示例中,@PreAuthorize注解中使用自定义的权限校验方法"myPermissionEvaluator.hasPermission()",指定了需要校验的对象为"#user",权限字符串为"edit"。

3. 自定义权限校验方法示例

下面是两个自定义权限校验方法的示例:

示例一:根据当前用户的角色动态校验权限

@Component
public class MyPermissionEvaluator implements PermissionEvaluator {

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if (authentication == null || !(targetDomainObject instanceof User)) {
            return false;
        }

        User user = (User) authentication.getPrincipal();
        List<String> roles = user.getRoles();

        if ("edit".equals(permission)) {
            if (roles.contains("ROLE_ADMIN")) {
                return true;
            } else if (roles.contains("ROLE_EDITOR")) {
                return ((User) targetDomainObject).getEditorId() == user.getId();
            }
        } else if ("view".equals(permission)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        throw new UnsupportedOperationException();
    }
}

在上述示例中,我们根据当前用户的角色动态判断用户的访问权限,如果用户具有ROLE_ADMIN角色,则允许访问;如果用户具有ROLE_EDITOR角色,则只能访问自己的文章。

示例二:根据权限字符串判断用户是否有权限访问资源

@Component
public class MyPermissionEvaluator implements PermissionEvaluator {

    @Autowired
    private ResourceDao resourceDao;

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if (authentication == null || !(targetDomainObject instanceof String)) {
            return false;
        }

        String url = (String) targetDomainObject;
        Resource resource = resourceDao.findByUrl(url);
        if (resource == null) {
            return false;
        }

        List<Role> roles = resource.getRoles();
        List<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toList());

        return authentication.getAuthorities().stream().anyMatch(authority -> roleNames.contains(authority.getAuthority()));
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        throw new UnsupportedOperationException();
    }
}

在上述示例中,我们根据权限字符串判断用户是否有权限访问资源,如果url可以匹配到Resource,则从中获取角色列表,再与当前用户的角色进行比较,如果有相同的角色,则允许用户访问。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何基于SpringSecurity的@PreAuthorize实现自定义权限校验方法 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java 基于tcp协议实现文件上传

    下面我来详细讲解一下Java基于tcp协议实现文件上传的完整攻略。 一、前置知识 在实现文件上传之前,需要具备以下知识: Java Socket编程基础知识 Java IO编程基础知识 文件上传的基本概念和流程 二、上传文件的流程 客户端连接服务器,向服务器发送需要上传的文件名、文件大小等信息 服务器接收到客户端发来的信息后,创建文件并打开输出流 客户端开始…

    Java 2023年5月19日
    00
  • Maven仓库分类的优先级

    当使用 Maven 构建项目时,Maven 会从一系列仓库中查找项目的依赖。 Maven 仓库分类的优先级体现在 Maven 会按照一定顺序去仓库中查找依赖。在 Maven 中,仓库可以分为以下几类,优先级由高到低排列: 本地仓库 (Local Repository) 中央仓库 (Central Repository) 远程仓库 (Remote Reposi…

    Java 2023年5月19日
    00
  • Android打包篇:Android Studio将代码打包成jar包教程

    我将为你详细讲解“Android打包篇:Android Studio将代码打包成jar包教程”的完整攻略。 一、前置条件 在进行此教程之前,需要保证以下条件已经满足: 你已经安装了Android Studio; 你已经构建了一个Android项目,并且需要将其中的某些代码打包成Jar包; 你已经了解过Java打包,熟悉Java打包命令。 二、步骤 接下来我们…

    Java 2023年5月26日
    00
  • Java Scanner用法案例详解

    Java Scanner用法案例详解 什么是Scanner类 Scanner类是一个标准的Java类,位于java.util包中。它提供了一种方便而且简单的方式用于读取用户输入的数据,例如,从键盘上读取数据。 Scanner类构造方法 Scanner类有以下几种构造方法: Scanner(File source):用于读取文件。 Scanner(InputS…

    Java 2023年5月26日
    00
  • 在Spring使用iBatis及配置讲解

    下面我将为您详细讲解“在Spring使用iBatis及配置讲解”的完整攻略。 前置知识 在学习使用iBatis前,我们需要掌握以下技能: 熟悉SQL语句的编写,理解SQL的基本语法和关键字; 熟悉Java语言的基础知识; 熟悉Spring框架的基本概念及使用方法。 环境准备 在使用iBatis时,我们需要准备以下环境: JDK:Java开发程序所必需的环境;…

    Java 2023年5月20日
    00
  • Lambda表达式的使用及注意事项

    Lambda表达式是Java8新引入的一种语法形式,可以用于简洁地定义匿名函数,常用于对集合进行筛选、映射等操作。下面将详细讲解Lambda表达式的使用及注意事项。 Lambda表达式的语法 Lambda表达式由三部分组成:参数列表、箭头符号和表达式或语句块。其基本格式为: (参数列表) -> {表达式或语句块} 例如,下面是一个Lambda表达式的例…

    Java 2023年5月19日
    00
  • springmvc的文件保存方法详解

    下面我将详细讲解SpringMVC的文件保存方法,内容如下: 1.文件上传流程 在介绍文件保存方法之前,先来了解一下文件上传的流程,SpringMVC的文件上传流程如下: 页面提交表单(form)数据和文件数据到服务器 服务器通过SpringMVC的DispatcherServlet分发请求到Controller Controller接收到请求后,通过调用S…

    Java 2023年6月15日
    00
  • 解决使用httpclient传递json数据乱码的问题

    解决使用HttpClient传递JSON数据乱码问题的攻略,我们可以从以下两个方面来考虑: 设置Http请求头中的Content-Type为application/json 将JSON数据的字符串转化为字节数组进行传输 下面将分别详细讲解这两个方面的解决方案以及代码示例。 设置Http请求头中的Content-Type为application/json Ht…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部