2023年6月20日发(作者:)

SpringSecurity怎样使⽤注解控制权限⼀般的系统在权限设计上,都会分为⾓⾊、权限(RDBC),复杂⼀点的可能会有⽤户组、组织之类的概念。⽤户的权限是写死的,对应于后台的接⼝或者资源,是没办法改变的,⼀般不对⽤户开放修改权限。管理员⽤户可以通过给⾓⾊分配权限的⽅式,来实现访问控制。所以当我们写过滤器,或者⽤⼀些安全框架时(⽐如Shiro,Spring Security),也需要将可变的“⾓⾊”,转化为不可变的“权限”,注⼊到框架中。具体的可以看我之前写的⼀篇()注⼊当前⽤户的权限后,就需要进⾏访问控制了。常见的做法有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 = t(4); if(i == 2) { ShelveTask(); } Page list = (taskDto); return (list); }hasAuthority可以替换成hasRole,虽然可以达到相同的⽬的,但是在使⽤的⽅法上还是有些不同的。hasRole要求内容必须以"ROLE_"开头,也是官⽅推荐的命名⽅式,否则没有效果。但是hasAuthority没有限制,数据库中怎样写的,代码⾥就怎么写。同样的功能的注解为什么要有两个名字呢。或许这么做可能在语义上⽐较清晰明确⼀点,将⾓⾊与权限这两个概念稍加区分。仔细想⼀下,确实有些⼩型的系统或许压根就不需要权限,只有给⽤户分配⾓⾊,没有给⾓⾊分配权限这⼀过程。这样的话,⾓⾊也是不可变的,就可以根据⾓⾊来做访问控制了。但考虑通⽤性,个⼈觉得⽤hasAuthority就可以了。SpringSecurity_权限注解@PreAuthorize、@PostAuthorizespring是如何实现对HTTP请求进⾏安全检查和资源使⽤授权的?实现过程由类AbstractSecurityInterceptor在beforeInvocation⽅法中完成,在beforeInvocation的实现中,⾸先,需要读取IoC容器中Bean的配置,在这些属性配置中配置了对HTTP请求资源的安全需求,⽐如,哪个⾓⾊的⽤户可以接⼊哪些URL请求资源,具体实现逻辑见:#与Web环境的接⼝FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter@PreAuthorize、@PostAuthorize注解实现逻辑继承根节点:SecurityMetaSource可以通过Spring注解声明,需要依赖类注⼊,实现权限灵活配置如:@Component("securityMetadataSource")public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSourcePrePostAnnotationSecurityMetadataSource类继承关系AbstractMethodSecurityMetadataSource类继承关系package t;

import tion;import ;import ist;import tion;import tions;import tionUtils;import Attribute;import ctMethodSecurityMetadataSource;import tils;

public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource { private final PrePostInvocationAttributeFactory attributeFactory; public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) { uteFactory = attributeFactory; }

public Collection getAttributes(Method method, Class targetClass) { if (laringClass() == ) { return ist(); } else { ("Looking for Pre/Post annotations for method '" + e() + "' on target class '" + targetClass + "'"); PreFilter preFilter = (PreFilter)notation(method, targetClass, ); PreAuthorize preAuthorize = (PreAuthorize)notation(method, targetClass, ); PostFilter postFilter = (PostFilter)notation(method, targetClass, ); PostAuthorize postAuthorize = (PostAuthorize)notation(method, targetClass, ); if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) { ("No expression annotations found"); return ist(); } else { String preFilterAttribute = preFilter == null ? null : (); String filterObject = preFilter == null ? null : Target(); String preAuthorizeAttribute = preAuthorize == null ? null : (); String postFilterAttribute = postFilter == null ? null : (); String postAuthorizeAttribute = postAuthorize == null ? null : (); ArrayList attrs = new ArrayList(2); PreInvocationAttribute pre = PreInvocationAttribute(preFilterAttribute, filterObject, preAuthorizeAttribute); if (pre != null) { (pre); }

PostInvocationAttribute post = PostInvocationAttribute(postFilterAttribute, postAuthorizeAttribute); if (post != null) { (post); }

Size(); return attrs; } } }

public Collection getAllConfigAttributes() { return null; }

private A findAnnotation(Method method, Class targetClass, Class annotationClass) { Method specificMethod = tSpecificMethod(method, targetClass); A annotation = notation(specificMethod, annotationClass); if (annotation != null) { (annotation + " found on specific method: " + specificMethod); return annotation; } else { if (specificMethod != method) { annotation = notation(method, annotationClass); if (annotation != null) { (annotation + " found on: " + method); return annotation; } }

annotation = notation(laringClass(), annotationClass); if (annotation != null) { (annotation + " found on: " + laringClass().getName()); return annotation; } else { return null; } } }}//注解开启权限@EnableResourceServer@EnableGlobalMethodSecuritySecurityContextHolder作为全局缓存,从上下⽂获取授权信息Authentication authentication = text().getAuthentication();Collection authorities = horities();上⾯权限列表初始化由具体实现类实现:public class User implements UserDetails, CredentialsContainer { ... private final Set authorities; ... //authorities权限列表 public User(String username, String password, Collection authorities) { this(username, password, true, true, true, true, authorities); }以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。

2023年6月20日发(作者:)

SpringSecurity怎样使⽤注解控制权限⼀般的系统在权限设计上,都会分为⾓⾊、权限(RDBC),复杂⼀点的可能会有⽤户组、组织之类的概念。⽤户的权限是写死的,对应于后台的接⼝或者资源,是没办法改变的,⼀般不对⽤户开放修改权限。管理员⽤户可以通过给⾓⾊分配权限的⽅式,来实现访问控制。所以当我们写过滤器,或者⽤⼀些安全框架时(⽐如Shiro,Spring Security),也需要将可变的“⾓⾊”,转化为不可变的“权限”,注⼊到框架中。具体的可以看我之前写的⼀篇()注⼊当前⽤户的权限后,就需要进⾏访问控制了。常见的做法有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 = t(4); if(i == 2) { ShelveTask(); } Page list = (taskDto); return (list); }hasAuthority可以替换成hasRole,虽然可以达到相同的⽬的,但是在使⽤的⽅法上还是有些不同的。hasRole要求内容必须以"ROLE_"开头,也是官⽅推荐的命名⽅式,否则没有效果。但是hasAuthority没有限制,数据库中怎样写的,代码⾥就怎么写。同样的功能的注解为什么要有两个名字呢。或许这么做可能在语义上⽐较清晰明确⼀点,将⾓⾊与权限这两个概念稍加区分。仔细想⼀下,确实有些⼩型的系统或许压根就不需要权限,只有给⽤户分配⾓⾊,没有给⾓⾊分配权限这⼀过程。这样的话,⾓⾊也是不可变的,就可以根据⾓⾊来做访问控制了。但考虑通⽤性,个⼈觉得⽤hasAuthority就可以了。SpringSecurity_权限注解@PreAuthorize、@PostAuthorizespring是如何实现对HTTP请求进⾏安全检查和资源使⽤授权的?实现过程由类AbstractSecurityInterceptor在beforeInvocation⽅法中完成,在beforeInvocation的实现中,⾸先,需要读取IoC容器中Bean的配置,在这些属性配置中配置了对HTTP请求资源的安全需求,⽐如,哪个⾓⾊的⽤户可以接⼊哪些URL请求资源,具体实现逻辑见:#与Web环境的接⼝FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter@PreAuthorize、@PostAuthorize注解实现逻辑继承根节点:SecurityMetaSource可以通过Spring注解声明,需要依赖类注⼊,实现权限灵活配置如:@Component("securityMetadataSource")public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSourcePrePostAnnotationSecurityMetadataSource类继承关系AbstractMethodSecurityMetadataSource类继承关系package t;

import tion;import ;import ist;import tion;import tions;import tionUtils;import Attribute;import ctMethodSecurityMetadataSource;import tils;

public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource { private final PrePostInvocationAttributeFactory attributeFactory; public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) { uteFactory = attributeFactory; }

public Collection getAttributes(Method method, Class targetClass) { if (laringClass() == ) { return ist(); } else { ("Looking for Pre/Post annotations for method '" + e() + "' on target class '" + targetClass + "'"); PreFilter preFilter = (PreFilter)notation(method, targetClass, ); PreAuthorize preAuthorize = (PreAuthorize)notation(method, targetClass, ); PostFilter postFilter = (PostFilter)notation(method, targetClass, ); PostAuthorize postAuthorize = (PostAuthorize)notation(method, targetClass, ); if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) { ("No expression annotations found"); return ist(); } else { String preFilterAttribute = preFilter == null ? null : (); String filterObject = preFilter == null ? null : Target(); String preAuthorizeAttribute = preAuthorize == null ? null : (); String postFilterAttribute = postFilter == null ? null : (); String postAuthorizeAttribute = postAuthorize == null ? null : (); ArrayList attrs = new ArrayList(2); PreInvocationAttribute pre = PreInvocationAttribute(preFilterAttribute, filterObject, preAuthorizeAttribute); if (pre != null) { (pre); }

PostInvocationAttribute post = PostInvocationAttribute(postFilterAttribute, postAuthorizeAttribute); if (post != null) { (post); }

Size(); return attrs; } } }

public Collection getAllConfigAttributes() { return null; }

private A findAnnotation(Method method, Class targetClass, Class annotationClass) { Method specificMethod = tSpecificMethod(method, targetClass); A annotation = notation(specificMethod, annotationClass); if (annotation != null) { (annotation + " found on specific method: " + specificMethod); return annotation; } else { if (specificMethod != method) { annotation = notation(method, annotationClass); if (annotation != null) { (annotation + " found on: " + method); return annotation; } }

annotation = notation(laringClass(), annotationClass); if (annotation != null) { (annotation + " found on: " + laringClass().getName()); return annotation; } else { return null; } } }}//注解开启权限@EnableResourceServer@EnableGlobalMethodSecuritySecurityContextHolder作为全局缓存,从上下⽂获取授权信息Authentication authentication = text().getAuthentication();Collection authorities = horities();上⾯权限列表初始化由具体实现类实现:public class User implements UserDetails, CredentialsContainer { ... private final Set authorities; ... //authorities权限列表 public User(String username, String password, Collection authorities) { this(username, password, true, true, true, true, authorities); }以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。