SpringSecurity怎样使用注解控制权限

网友投稿 960 2023-01-05

SpringSecurity怎样使用注解控制权限

SpringSecurity怎样使用注解控制权限

一般的系统在权限设计上,都会分为角色、权限(RDBC),复杂一点的可能会有用户组、组织之类的概念。

用户的权限是写死的,对应于后台的接口或者资源,是没办法改变的,一般不对用户开放修改权限。

管理员用户可以通过给角色分配权限的方式,来实现访问控制。

所以当我们写过滤器,或者用一些安全框架时(比如Shiro,Spring Security),也需要将可变的“角色”,转化为不可变的“权限”,注入到框架中。

具体的可以看我之前写的一篇(Spring Security整合jwt完整版)

注入当前用户的权限后,就需要进行访问控制了。

常见的做法有

1、路径比对

之前有个项目用过一次,定义一个过滤器,添加到security的过滤链中,在这个过滤器中做这么一件事:

分析当前访问路径所需要的权限,检查当前用户是否具有该权限,做一个对比,根据对比结果来决定当前用户是否可以访问该资源。

这种做法的好处是代码的入侵性不高,不需要再每个接口上加注解。但相对来说,显得不那么直观,可读性比较差,所以这次换个方法。

2、使用注解的方式

SpringSecurity使用注解来控制访问时,需要提前开启这个功能。

在配置类上加上注解

@Configuration

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class SecurityConfig extends WebSecurityConfigurerAdapter {

在接口中如此使用

/**

* 条件查询

*/

@PreAuthorize("hasAuthority('IMPORT:SELECT')")

@ApiOperation(value = "查询")

@GetMapping("/list")

public R> list(TaskDto taskDto){

//测试阶段,随机生成任务

Random random = new Random();

//todo

int i = random.nextInt(4);

if(i == 2) {

metroServerAdapterService.reloadShelveTask();

}

Page list = taskService.list(taskDto);

return R.ok(list);

}

hasAuthority可以替换成hasRole,虽然可以达到相同的目的,但是在使用的方法上还是有些不同的。

hasRole要求内容必须以"ROLE_"开头,也是官方推荐的命名方式,否则没有效果。但是hasAuthority没有限制,数据库中怎样写的,代码里就怎么写。

同样的功能的注解为什么要有两个名字呢。或许这么做可能在语义上比较清晰明确一点,将角色与权限这两个概念稍加区分。

仔细想一下,确实有些小型的系统或许压根就不需要权限,只有给用户分配角色,没有给角色分配权限这一过程。这样的话,角色也是不可变的,就可以根据角色来做访问控制了。

但考虑通用性,个人觉得用hasAuthority就可以了。

SpringSecurity_权限注解@PreAuthorize、@PostAuthorize

spring是如何实现对HTTP请求进行安全检查和资源使用授权的?

实现过程由类AbstractSecurityInterceptor在beforeInvocation方法中完成,在beforeInvocation的实现中,

首先,需要读取IoC容器中Bean的配置,在这些属性配置中配置了对HTTP请求资源的安全需求,

比如,哪个角色的用户可以接入哪些URL请求资源,具体实现逻辑见:

#与Web环境的接口FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter

@PreAuthorize、@PostAuthorize注解实现逻辑

继承根节点:SecurityMetaSource

可以通过Spring注解声明,需要依赖类注入,实现权限灵活配置如:

@Component("securityMetadataSource")

public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource

PrePostAnnotationSecurityMetadataSource类继承关系

AbstractMethodSecurityMetadataSource类继承关系

package org.springframework.security.access.prepost;

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Collections;

import org.springframework.core.annotation.AnnotationUtils;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource;

import org.springframework.util.ClassUtils;

public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {

private final PrePostInvocationAttributeFactory attributeFactory;

public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {

this.attributeFactory = attributeFactory;

}

public Collection getAttributes(Method method, Class> targetClass) {

if (method.getDeclaringClass() == Object.class) {

HHEWc return Collections.emptyList();

} else {

this.logger.trace("Looking for Pre/Post annotations for method '" + method.getName() + "' on target class '" + targetClass + "'");

PreFilter preFilter = (PreFilter)this.findAnnotation(method, targetClass, PreFilter.class);

PreAuthorize preAuthorize = (PreAuthorize)this.findAnnotation(method, targetClass, PreAuthorize.class);

PostFilter postFilter = (PostFilter)this.findAnnotation(method, targetClass, PostFilter.class);

PostAuthorize postAuthorize = (PostAuthorize)this.findAnnotation(method, targetClass, PostAuthorize.class);

if (preFilter == null && preAuthorize == null && postFilter == null && pohttp://stAuthorize == null) {

this.logger.trace("No expression annotations found");

return Collections.emptyList();

} else {

String preFilterAttribute = preFilter == null ? null : preFilter.value();

String filterObject = preFilter == null ? null : preFilter.filterTarget();

String preAuthorizeAttribute = preAuthorize == null ? null : preAuthorize.value();

String postFilterAttribute = postFilter == null ? null : postFilter.value();

String postAuthorizeAttribute = postAuthorize == null ? null : postAuthorize.value();

ArrayList attrs = new ArrayList(2);

PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(preFilterAttribute, filterObject, preAuthorizeAttribute);

if (pre != null) {

attrs.add(pre);

}

PostInvocationAttribute post = this.attributeFactory.createPostInvocationAttribute(postFilterAttribute, postAuthorizeAttribute);

if (post != null) {

attrs.add(post);

}

attrs.trimToSize();

return attrs;

}

}

}

public Collection getAllConfigAttributes() {

return null;

}

private A findAnnotation(Method method, Class> targetClass, Class annotationClass) {

Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);

A annotation = AnnotationUtils.findAnnotation(specificMethod, annotationClass);

if (annotation != null) {

this.logger.debug(annotation + " found on specific method: " + specificMethod);

return annotation;

} else {

if (specificMethod != method) {

annotation = AnnotationUtils.findAnnotation(method, annotationClass);

if (annotation != null) {

this.logger.debug(annotation + " found on: " + method);

return annotation;

}

}

annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);

if (annotation != null) {

this.logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());

return annotation;

} else {

return null;

}

}

}

}

//注解开启权限

@EnableResourceServer

@EnableGlobalMethodSecurity

SecurityContextHolder作为全局缓存,从上下文获取授权信息

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

Collection extends GrantedAuthority> authorities = authentication.getAuthorities();

上面权限列表初始化由具体实现类实现:

public class User implements UserDetails, CredentialsContainer {

...

private final Set authorities;

...

//authorities权限列表

public User(String username, String password, Collection extends GrantedAuthority> authorities) {

this(username, password, true, true, true, true, authorities);

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:职业考试app运营模式(职业考试APP)
下一篇:苏州企业app开发(苏州园区软件公司)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~