下面是详细攻略。
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是写死的,如果我们需要根据不同的业务需求来动态判断用户的访问权限,就需要自定义权限校验方法。下面是自定义权限校验方法的步骤:
- 创建一个自定义的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();
}
}
- 在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技术站