一、SpEL审核在SpringSecurity中,@PreAuthorize、@PostAuthorize等注解都支持SpEL表达式。在SpEL表达式中,如果直接写要执行的方法名,则表示该方法是RootObject对象中的一个方法。如果要执行其他对象的方法,还需要写对象的名称,例如下面两个例子:@PreAuthorize("hasAuthority('system:user:add')")publicStringadd(){return"add";}在上面的例子中,表达式中的方法是hasAuthority,对象名没有写,那么就说明这个方法是SpEL中RootObject对象中的一个方法。@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")@GetMapping("/list")publicTableDataInfolist(SysOperLogoperLog){startPage();Listlist=operLogService.selectOperLogList(operLog);returngetDataTable(list);}在上面的例子中,权限注解中的表达式方法是@ss.hasPermi('monitor:operlog:list'),其中ss指的是Spring容器中的一个对象名,hasPermi是is这个对象的一个??方法。好了,通过前面几篇的学习,这些基础知识大家已经掌握了。2.如何定制其实上面给出的第二个例子就是一个定制的例子。但是这种定制方式太自由了,自由到SpringSecurity架构内部都做不到。所以,今天想和小伙伴们聊一聊如何在不使用第三方对象的情况下定义一个权限判断表达式。首先小伙伴们都知道,我们在@PreAuthorize注解中使用的不加对象名就可以调用的权限方法,比如hasAuthority、hasPermission、hasRole、hasAnyRole等,基本上都是SecurityExpressionRoot及其子类提供的。Said由MethodSecurityExpressionRoot类提供。MethodSecurityExpressionRoot类实际上继承自SecurityExpressionRoot,只是增加了过滤对象和返回值对象。我们看一下MethodSecurityExpressionRoot的方法总结:我们看一下SecurityExpressionRoot中的方法:这些都是RootObject对象中的方法,在@PreAuthorize注解中我们可以使用的所有方法。所以现在我们想在已有的方法上继续扩展新的方法,那么我们可以通过自定义类继承SecurityExpressionRoot对象,扩展RootObject对象,继续在对象中添加新的方法,进而实现自定义的权限表达式.好吧,我们开始吧,我们开始吧!本文的案例是在上一篇的基础上继续完成的,这里就不从头写了。3.自定义ExpressionRoot首先我们自定义一个继承SecurityExpressionRoot并实现了MethodSecurityExpressionOperations接口的类(本来直接继承MethodSecurityExpressionRoot就可以了,但是因为这个类不是public的,所以不能继承,所以我们只实现了MethodSecurityExpressionOperations接口接口):publicclassCustomSecurityExpressionRootextendsSecurityExpressionRootimplementsMethodSecurityExpressionOperations{privateObjectfilterObject;私有对象返回对象;私有AntPathMatcherantPathMatcher=newAntPathMatcher();/***创建一个新实例**@param身份验证。*/publicCustomSecurityExpressionRoot(Authenticationauthentication){super(authentication);}/***判断当前对象是否有某个权限*@parampermission*@return*/publicbooleanhasPermission(Stringpermission){//获取当前登录用户其拥有的权限Collectionauthorities=authentication.getAuthorities();为了(GrantedAuthorityauthority:authorities){if(antPathMatcher.match(authority.getAuthority(),permission)){返回真;}}返回假;}/***是不是装备多个权限中的任意一个权限*@parampermissions*@return*/publicbooleanhasAnyPermissions(String...permissions){if(permissions==null||permissions.length==0){返回假;}集合authorities=authentication.getAuthorities();for(GrantedAuthorityauthority:authorities){for(Stringpermission:permissions){if(antPathMatcher.match(authority.getAuthority(),permission)){返回真;}}}返回假;}publicbooleanhasAllPermissions:(String...permissions){Collectionauthorities=authentication.getA当局();如果(权限==null||permissions.length==0){returnfalse;}for(Stringpermission:permissions){booleanflag=false;for(GrantedAuthorityauthority:authorities){if(antPathMatcher.match(authority.getAuthority(),permission)){flag=true;}}if(!flag){返回false;}}返回真;}@OverridepublicvoidsetFilterObject(ObjectfilterObject){this.filterObject=filterObject;}@OverridepublicObjectgetFilterObject(){returnfilterObject;}@OverridepublicvoidsetReturnObject(ObjectreturnObject){this.returnObject=returnObject;}@OverridepublicObjectgetReturnObject(){returnreturnObject;}@OverridepublicObjectgetThis(){返回这个;}}加了@Override注解的方法都是普通方法。没什么可说的。我们主要实现了三个方法,分别是:hasPermission:判断当前用户是否拥有给定的权限。hasAnyPermissions:判断当前用户是否拥有给定的多个权限之一。hasAllPermissions:判断当前用户是否拥有所有给定的权限。这里我不再重复逻辑,它只是基本的Java语法。另外,使用AntPathMatcher进行比较是为了支持通配符。这个在之前的文章中已经提到,这里不再赘述。SpringSecurity中,MethodSecurityExpressionRoot的配置是通过DefaultMethodSecurityExpressionHandler来完成的,现在我们自定义了CustomSecurityExpressionRoot,那也得有一个Handler来配置CustomSecurityExpressionRoot,所以,再来一个类继承自DefaultMethodSecurityExpressionHandler,如下:publicclassCustomMethodSecurityExpressionHandlerextendsDefaultMethodSecurityExpressionHandler{@OverrideprotectedMethodSecurityExpressionOperationscreateSecurityExpressionRoot(Authenticationauthentication,MethodInvocationinvocation){CustomSecurityExpressionRootroot=newCustomSecurityExpressionRoot(authentication);root.setTrustResolver(getTrustResolver());root.setPermissionEvaluator(getPermissionEvaluator());root.setRoleHierarchy(getRoleHierarchy());returnroot;}}CreateaCustomSecurityExpressionRootobjectinthecreateSecurityExpressionRootmethod.Theobject'sTrustResolver,authorityevaluator,androlehierarchycanallusethedefaultscheme.配置完成后,再次配置CustomMethodSecurityExpressionHandlerBean,如下:@BeanCustomMethodSecurityExpressionHandlercustomMethodSecurityExpressionHandler(){returnnewCustomMethodSecurityExpressionHandler();}好了,注入成功。接下来,我们可以在权限注解中使用这个自定义方法:@PreAuthorize("hasPermission('system:user:add')")publicStringadd(){return"add";}这个自定义权限的思想表达,归根结底还是在SpringSecurity体系中发挥作用。我个人觉得这个方法比较合理。