pdf secured_使您的Spring Security @Secured注释更干燥

pdf secured

最近,Grails用户邮件列表中的一个用户想知道在定义@Secured注释时如何减少重复 。 在Java批注中指定属性的规则非常严格,因此我看不到直接执行他所要求的方法的方法。

使用Groovy并没有真正的帮助,因为Groovy类中的注释大部分与Java中的注释几乎相同(数组值的语法除外)。 当然,Groovy现在支持注释中的闭包,但这需要在插件中进行代码更改。 但是后来我想到了Jeff Brown最近在缓存插件中所做的一些工作。

Spring的缓存抽象API包括三个注释。 @Cacheable@CacheEvict@CachePut 。 我们正在考虑支持比这些注释所允许的更多的配置选项,但是由于您无法对注释进行子类化,因此我们决定使用AST转换来查找这些注释的版本(当前具有与Spring注释相同的属性)并进行转换有效的Spring注释。 因此,我查看了Jeff的代码 ,它最终成为解决此问题的基础。

无法使用代码外部化权限列表,因为您无法控制编译顺序。 因此,我最终得到了一个不完美但可以使用的解决方案–我在项目根目录中寻找一个属性文件( roles.properties )。 格式很简单–密钥是每个权限列表的名称,值是权限名称的列表,以逗号分隔。 这是一个例子:

 admins=ROLE_ADMIN, ROLE_SUPERADMIN  switchUser=ROLE_SWITCH_USER  editors=ROLE_EDITOR, ROLE_ADMIN 

这些键是用于新@Authorities批注的值:

 package grails.plugins.springsecurity.annotation;  import java.lang.annotation.Documented;  import java.lang.annotation.ElementType;  import java.lang.annotation.Inherited;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;  import org.codehaus.groovy.transform.GroovyASTTransformationClass;  /** * @author Burt Beckwith */  @Target ({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})  @Retention (RetentionPolicy.RUNTIME)  @Inherited  @Documented  @GroovyASTTransformationClass ( "grails.plugins.springsecurity.annotation.AuthoritiesTransformation" )  public @interface Authorities { /** * The property file key; the property value will be a * comma-delimited list of role names. * @return the key */ String value();  } 

例如,这是一个使用新注释的控制器:

 @Authorities ( 'admins' )  class SecureController { @Authorities ( 'editors' ) def someAction() { ... }  } 

这等效于此控制器(如果使用@Authorities反编译,则会看到两个注释):

 @Secured ([ 'ROLE_ADMIN' , 'ROLE_SUPERADMIN' ])  class SecureController { @Secured ([ 'ROLE_EDITOR' , 'ROLE_ADMIN' ]) def someAction() { ... }  } 

AST转换类使用属性文件中指定的角色名称查找@Authorities批注,加载属性文件并添加新的@Secured批注(不会删除@Authorities批注):

 package grails.plugins.springsecurity.annotation;  import grails.plugins.springsecurity.Secured;  import java.io.File;  import java.io.FileReader;  import java.io.IOException;  import java.util.ArrayList;  import java.util.List;  import java.util.Properties;  import org.codehaus.groovy.ast.ASTNode;  import org.codehaus.groovy.ast.AnnotatedNode;  import org.codehaus.groovy.ast.AnnotationNode;  import org.codehaus.groovy.ast.ClassNode;  import org.codehaus.groovy.ast.expr.ConstantExpression;  import org.codehaus.groovy.ast.expr.Expression;  import org.codehaus.groovy.ast.expr.ListExpression;  import org.codehaus.groovy.control.CompilePhase;  import org.codehaus.groovy.control.SourceUnit;  import org.codehaus.groovy.transform.ASTTransformation;  import org.codehaus.groovy.transform.GroovyASTTransformation;  import org.springframework.util.StringUtils;  /** * @author Burt Beckwith */  @GroovyASTTransformation (phase=CompilePhase.CANONICALIZATION)  public class AuthoritiesTransformation implements ASTTransformation { protected static final ClassNode SECURED = new ClassNode(Secured. class ); public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) { try { ASTNode firstNode = astNodes[ 0 ]; ASTNode secondNode = astNodes[ 1 ]; if (!(firstNode instanceof AnnotationNode) || !(secondNode instanceof AnnotatedNode)) { throw new RuntimeException( "Internal error: wrong types: " + firstNode.getClass().getName() + " / " + secondNode.getClass().getName()); } AnnotationNode rolesAnnotationNode = (AnnotationNode) firstNode; AnnotatedNode annotatedNode = (AnnotatedNode) secondNode; AnnotationNode secured = createAnnotation(rolesAnnotationNode); if (secured != null ) { annotatedNode.addAnnotation(secured); } } catch (Exception e) { // TODO e.printStackTrace(); } } protected AnnotationNode createAnnotation(AnnotationNode rolesNode) throws IOException { Expression value = rolesNode.getMembers().get( "value" ); if (!(value ConstantExpression)) { (!(value instanceof ConstantExpression)) { // TODO System.out.println( "annotation @Authorities value isn't a ConstantExpression: " + value); return null ; } String fieldName = value.getText(); String[] authorityNames = getAuthorityNames(fieldName); if (authorityNames == null ) { return null ; } return buildAnnotationNode(authorityNames); } protected AnnotationNode buildAnnotationNode(String[] names) { AnnotationNode securedAnnotationNode = new AnnotationNode(SECURED); List<Expression> nameExpressions = new ArrayList<Expression>(); for (String authorityName : names) { nameExpressions.add( new ConstantExpression(authorityName)); } securedAnnotationNode.addMember( "value" , new ListExpression(nameExpressions)); return securedAnnotationNode; } protected String[] getAuthorityNames(String fieldName) throws IOException { Properties properties = new Properties(); File propertyFile = new File( "roles.properties" ); if (!propertyFile.exists()) { // TODO System.out.println( "Property file roles.properties not found" ); return null ; } properties.load( new FileReader(propertyFile)); Object value = properties.getProperty(fieldName); if (value == null ) { // TODO System.out.println( "No value for property '" + fieldName + "No value for property '" + fieldName + "'" ); return null ; } List<String> names = new ArrayList<String>(); String[] nameArray = StringUtils.commaDelimitedListToStringArray( value.toString()) for (String auth : nameArray) { auth = auth.trim(); if (auth.length() > 0 ) { names.add(auth); } } return names.toArray( new String[names.size()]); }  } 

我可能会在某个时候将其包含在插件中-我已提醒您创建了JIRA问题 -但现在您可以将这两个类复制到应用程序的src / java文件夹中,并在项目根目录中创建一个roles.properties文件。 每当您要添加或删除条目或从条目添加或删除角色名称时,请更新属性文件,运行grails cleangrails compile以确保使用最新值。

参考:在An Solipsists博客上,由我们的JCG合作伙伴 Burt Beckwith 使您的Spring Security @Secured注释更加干燥 。


翻译自: https://www.javacodegeeks.com/2012/06/make-your-spring-security-secured.html

pdf secured

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

51单片机按键控制数码管0~9_51单片机外部中断

前面为大家介绍的点亮LED灯、数码管、按键只用到了51单片机的IO资源&#xff0c;我们要是仅仅用单片机点灯、操作数码管&#xff0c;那可真是大才小用了。这些都只是51单片机资源的冰山一角&#xff0c;51单片机还有好多的功能&#xff0c;我后面将为大家一一介绍。今天为大家介…

IIS7开启gZip动态压缩

1.安装动态压缩模块&#xff1a; 安装过程可能的报错&#xff1a;This application has requested the Runtime to terminate it in an unusual way. 解决办法>> 报错&#xff1a;错误: 尝试安装 动态内容压缩 失败&#xff0c;错误代码为 0x8007000E。 存储空间不足&am…

mysql查询不重复记录数_mysql查询不重复的行内容,不重复的记录数.count,distinct

有这么一个表 记录了id, p_id, p_name , p_content , p_time 1 343 aaa aaaaaa 2012-09-01 2 344 bbb bbbbbb 2012-09-02 3 321 ccc cccccccc 2012-09-03 4 343 aaa aaaaaa 2012-09-04 想查询不重复的行的内容,并且输出 p_sum ( 产品p_id出现重复的次数) sele有这么一个表记录了…

使用Java中的FileChannel和ByteBuffer在文件中读取/写入文件

过去&#xff0c;我讨论过RandomAccessFile以及如何将其用于在Java中进行更快的IO&#xff0c;在本Java NIO教程中&#xff0c;我们将了解如何通过使用FileChannel和ByteBuffer来使用读/写数据。 Channel提供了一种从文件读取数据的替代方法&#xff0c;它提供了比InputStream…

字符,字符串,int之间互相转换

字符转换成字符串&#xff1a;String str String.valueOf(ch); 字符转换成int&#xff1a; int a ch; 字符串转换成字符&#xff1a;char ch str.charAt(0); 字符串转换成Int&#xff1a;只包含数字的字符串可以通过Integer.parseInt(str)转换为int&#xff0c;但是包含字母…

mysql 导入百万级数据 几种 java_Java 修行第034天--执行计划及其使用--Oracle数据导入导出--第三章MySQL使用...

执行计划中牢记几句话:-- 尽量避免是*代替所有列,编写查询语句时使用具体列名代替*,可以防止全表扫描-- 尽可能少的使用like关键字进行模糊查询-- 建立适当的索引可以提高查询效率十三. 执行计划--通过PL/SQL Developer查看查询的1 执行计划是一条查询语句在Oracle中的执行过程…

10g添加用户 oracle_oracle 10g中如何创建用户

登录身份 说明sys/change_on_install SYSDBA或SYSOPER 不能以NORMAL登录&#xff0c;可作为默认的系统管理员system/manager SYSDBA或NORMAL 不能以SYSOPER登录&#xff0c;可作为默认的系统管理员sysman/oem_temp sysman 为oms的用户名scott/tiger NORMAL 普通用户aqadm /aqad…

摄像头分辨率怎么调整_亿联CAM50 - 智能话机专属高清摄像头

亿联CAM50是通过USB连接的高清视频摄像机&#xff0c;适用于亿联桌面高端智能话机&#xff08;SIP-T58V和SIP-T58A&#xff09;&#xff0c;致力于提供一流的个人视频通信体验&#xff0c;优化视频协作。CAM50高清摄像机即插即用&#xff0c;无需额外安装驱动软件&#xff0c;也…

C orm mysql_Simple MySQL-C ORM

当你需要在纯C语言的应用程序中访问 MySQL 表中的数据时&#xff0c;是非常繁琐的事情&#xff0c;而该框架可以帮你大量的简化编码的工作&#xff0c;该框架采用 Python 开发&#xff0c;适用于 C 语言程序。示例代码&#xff1a;#include #include #include #include int mai…

jdbc:log4jdbc_使用Log4jdbc记录JDBC操作

jdbc:log4jdbc当我们开发任何应用程序&#xff0c;完成它或结束其任何模块时&#xff0c;我们都会开始优化过程。 大多数应用程序都包含数据库访问权限&#xff0c;如果您使用的是ORM &#xff0c;则可能会使用hibernate 。 优化Hibernate持久层&#xff0c;要求准备阅读&#…

Mac 编译安装 Redis-3.2.3

Redis官方下载地址&#xff1a;http://redis.io/download Redis安装 cd /usr/local/src/redis-3.2.3 sudo make sudo make installcp ./src/redis-benchmark /usr/local/redis/redis-3.2 cp ./src/redis-check-aof /usr/local/redis/redis-3.2 cp ./src/redis-check-rdb /usr/l…

linux c mysql教程_linux下c操作mysql之增删改查

书接上文,继续进行linux 下c操作mysql。1.创建表/插入数据mysql> desc children-> ;----------------------------------------------------------| Field | Type| Null | Key | Default | Extra |----------------------------------------------------------| childno …

ios系统python编译器_MacBook如何安装Python编译器-百度经验

编程是一门需要动手实践的技能&#xff0c;由于Python的性能&#xff0c;许多人都将其作为学习编程的入门语言。而要想学好Python&#xff0c;首先要在电脑上安装Python&#xff0c;并安装一个可以解释Python的文本编辑器。在此以在MacBook上安装Sublime Text为例。 工具/原料 …

jvm需要多长时间进行转义分析? 可能比您想象的要长。

这篇文章着眼于转义分析&#xff0c;特别是jvm在运行的程序中执行转义分析需要多长时间。 我做了一些观察&#xff0c;但目前还没有全部解释。 作为介绍&#xff0c;让我们绕道看看jvm -Xcomp中一个鲜为人知且使用更少的标志&#xff08;这将是一件好事&#xff09;。 该标志…

Java补漏(一)

&#xfeff;&#xfeff;第一章前言 在学长的建议下&#xff0c;为了弥补之前学Java漏下的或者不是非常清楚的知识点&#xff0c;买了本蛮好的教科书-《Java学习笔记&#xff08;JDK6&#xff09;》&#xff0c;正式又一次学习。为了记下一些让我恍然大悟的知识。写了本文档。…

子集和问题 算法_子集问题 主要是去重算法

给定一个可能包含重复元素的整数数组 nums&#xff0c;返回该数组所有可能的子集&#xff08;幂集&#xff09;。说明&#xff1a;解集不能包含重复的子集。示例:输入: [1,2,2]输出:[[2],[1],[1,2,2],[2,2],[1,2],[]]

mysql存储引擎使用教程_mysql教程:如何写MySQL存储引擎

在MySQL 5.1中开发一个存储引擎已经是比较方便了。所谓存储引擎实际上是按照MySQL的约定&#xff0c;提供某些接口的实现而已&#xff0c;如MySQL插入一条记录时将调用write_row方法&#xff0c;通过索引检索时将调用index_read和index_next方法等。MySQL与存储引擎之间的接口主…

express中connect-flash中间件的使用

在学习node的时候&#xff0c;flash是困扰我最久的一个中间件&#xff0c;之前一直都没有很好的理解&#xff0c;这里做一个总结。 参考自&#xff1a;http://yunkus.com/connect-flash-usage/ 什么是flash&#xff1f; The flash is a special area of the session used for s…

spring environment_程序员:Spring项目中简单几步实现多个动态数据源切换

每一个请求与其他的用户是面对不同的数据库&#xff0c;这就需要用到动态数据源切换&#xff0c;来满足不同数据库、不同数据表(不同数据源)的灵活调用。动态数据源切换满足mysql、oracle等主流数据库进行动态数据源切换。使用方法在 WEB-INF 目录下建立 lib 目录&#xff0c;并…

算法笔记_163:算法提高 最大乘积(Java)

目录 1 问题描述 2 解决方案 1 问题描述 问题描述对于n个数&#xff0c;从中取出m个数&#xff0c;如何取使得这m个数的乘积最大呢&#xff1f;输入格式第一行一个数表示数据组数每组输入数据共2行&#xff1a;第1行给出总共的数字的个数n和要取的数的个数m&#xff0c;1<n&…