安全是每个实际的应用所必需面对的问题。但是,安全是个技术活,没有相当的功底是搞不定的。况且,DRY(don't repeat yourself)一直是我们的信条。所以,Spring Security 成了一个非常不错的选项。
Grails 约定优先的策略能够带来很大的便利,于是,两者的结合就是顺理成章的事情。
网上相关的帖子很多,经测试,总结下来是这样几个步骤。创建Grailsig程序不多赘述。以下的步骤是在程序创建完成后。
- 引入相应的插件。编辑build.gradle文件,dependencies中引入下列插件。
compile 'org.grails.plugins:spring-security-core:3.2.3'
compile 'org.grails.plugins:spring-security-ui:4.0.0.M1' // 针对Grails 3.3
compile 'org.grails.plugins:spring-security-rest:2.0.0.RC1'
- spring-security-core是核心插件,注意与Grails版本的匹配。如果Grails是3.3X就采用3.1以上的core。具体的匹配关系可以参考spring-security-core的说明。
- spring-security-ui是界面相关的插件,可以提供几个可用的查询,配置界面。也存在版本匹配的问题。
- 如果是些普通的web程序,只引入核心插件就够了。
- spring-security-rest插件是为了相应rest方式访问而设计的。引入这个插件就可以相应后端ajax或者axios发来的请求。不过,也存在版本匹配的问题。对于Grails 3.X,要用2.X的rest插件。
- 更需要注意的是,2.0.0.M2,2.0.0.RC1也有关键的变化:
- M2之前,用户的令牌采用JWT方式,有缺省的秘钥。RC1中没有了,所以,版本用错了,无法启动。会出错:java.lang.IllegalArgumentException: The specified token domain class 'null' is not a domain class
- 解决方案有两种:
- 或者引入相应的其他插件,用于存储用户令牌。比如spring-security-rest-gorm,将令牌存储到数据库中。
- 或者,自己给秘钥赋值(后面具体列出)。
- 执行插件的脚本文件,生成关键代码。最简单的命令就是“s2-quickstart cn.edu.cup.system User Role”。生成用户、角色两个关键的域类。同时生成application.groovy,放在conf目录下。
-
// Added by the Spring Security Core plugin: grails.plugin.springsecurity.userLookup.userDomainClassName = 'cn.edu.cup.system.User' grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'cn.edu.cup.system.UserRole' grails.plugin.springsecurity.authority.className = 'cn.edu.cup.system.Role' grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/', access: ['permitAll']], [pattern: '/error', access: ['permitAll']], [pattern: '/index', access: ['permitAll']], [pattern: '/index.gsp', access: ['permitAll']], [pattern: '/shutdown', access: ['permitAll']], [pattern: '/assets/**', access: ['permitAll']], [pattern: '/**/js/**', access: ['permitAll']], [pattern: '/**/css/**', access: ['permitAll']], [pattern: '/**/images/**', access: ['permitAll']], [pattern: '/**/favicon.ico', access: ['permitAll']] ] grails.plugin.springsecurity.filterChain.chainMap = [ [pattern: '/assets/**', filters: 'none'], [pattern: '/**/js/**', filters: 'none'], [pattern: '/**/css/**', filters: 'none'], [pattern: '/**/images/**', filters: 'none'], [pattern: '/**/favicon.ico', filters: 'none'], [pattern: '/**', filters: 'JOINED_FILTERS'] ]
自动生成的代码包括三个部分。第一部分是配置用户名域类的名字,角色域类的名字,以及用户授权域类的名字。
-
- 根据自己的需要,对安全插件进行必要的配置。如果rest采用M2版本,现在就可以用了。
- 如果采用RC1版本,就需要在application.groovy中增加一句,给JWT秘钥赋值。注意,如果不加这一句,系统会给出一个提示,结果提示中所列出来的对象的包名是错的,多了一个conf。具体的赋值语句如下:
grails.plugin.springsecurity.rest.token.storage.jwt.secret = '01234567890123456789012345678901'
秘钥的长度是有要求的,至少32个字符。
经过上述步骤,安全组件就基本正常可用了。接下来,就需要按照自己的选择,设置用户功能的安全性即可。