作者: 伯特·贝克威思,贝弗利塔尔博特
版本: 1.2.7.3
1. 创建Grails应用程序
$ grails create-app bookstore
$ cd bookstore
2. 安装该插件
$ grails install-plugin spring-security-core
3. 创建User和 Role 领域类。
$ grails s2-quickstart com.testapp User Role
You can choose your names for your domain classes and package; these arejust examples.
依据你的数据库,有些领域类的命名可能会受到限制, 尤其是那些与安全相关的。在创建诸如 "User"或者 "Group"为名的领域类之前, 请确认它们在你的数据库中不是被保护的关键字。
脚本自动创建了User类:
package com.testapp
package test
class User {
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static constraints = {
username blank: false, unique: true
password blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities(){
UserRole.findAllByUser(this).collect {it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password =springSecurityService.encodePassword(password)
}
}
早期版本的插件没有包括密码加密逻辑的域类,但代码很干净。
Role类也是脚本自动创建:
package com.testapp
class Role {
String authority
static mapping = {
cache true
}
static constraints = {
authority blank: false, unique: true
}
}
还创建了一个UserRole领域类来映射 many-to-many 连接类:
package com.testapp
import org.apache.commons.lang.builder.HashCodeBuilder
class UserRole implements Serializable {
User user
Role role
boolean equals(other) {
if (!(other instanceof UserRole)) {
returnfalse
}
other.user?.id == user?.id&&
other.role?.id == role?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (user) builder.append(user.id)
if (role) builder.append(role.id)
builder.toHashCode()
}
static UserRole get(long userId, long roleId) {
find 'from UserRole whereuser.id=:userId and role.id=:roleId',
[userId: userId, roleId:roleId]
}
static UserRole create(User user, Role role, boolean flush = false) {
new UserRole(user: user, role:role).save(flush: flush, insert: true)
}
staticboolean remove(User user, Role role, boolean flush = false) {
UserRole instance =UserRole.findByUserAndRole(user, role)
if (!instance) {
returnfalse
}
instance.delete(flush: flush)
true
}
static void removeAll(User user) {
executeUpdate 'DELETE FROMUserRole WHERE user=:user', [user: user]
}
static mapping = {
id composite: ['role', 'user']
version false
}
}
还自动创建了几个 UI 控制器和 GSP页面:
· grails-app/controllers/LoginController.groovy
· grails-app/controllers/LogoutController.groovy
· grails-app/views/auth.gsp
· grails-app/views/denied.gsp
脚本还编辑了grails-app/conf/Config.groovy ,为生成的领域类添加了一些配置,请确认这些修改是正确的。
这些自动生成的文件并不是插件的一部分 –它们都是你的应用程序文件。它们帮助你开始,所以你可以按照自己的喜好去修改。它们包含了插件的最低需求。
插件不支持对所生成领域类的 CRUD 动作和 GSP页面;spring-security-ui插件 会为这些提供一个UI。现在你需要在grails-app/conf/BootStrap.groovy中预置一些用户和角色 (参看第7步)。
4. 创建一个被role限制使用的控制器
$ grails create-controller com.testapp.Secure
这行命令在创建一个控制器类:grails-app/controllers/com/testapp/SecureController.groovy。添加一些输出内容可以验证控制器工作是否正常。
package com.testapp
class SecureController {
def index = {
render 'Secure access only'
}
}
5. 启动服务
$ grails run-app
6. 导航到http://localhost:8080/bookstore/secure, 在进入secure页面之前 你看不到登陆页面。
7. 停止服务,编辑 grails-app/conf/BootStrap.groovy 文件,添加你需要的安全部件。
import com.testapp.Role
import com.testapp.User
import com.testapp.UserRole
class BootStrap {
def init = { servletContext ->
def adminRole = new Role(authority:'ROLE_ADMIN').save(flush: true)
def userRole = new Role(authority:'ROLE_USER').save(flush: true)
def testUser = new User(username:'me', enabled: true, password: 'password')
testUser.save(flush: true)
UserRole.create testUser,adminRole, true
assert User.count() == 1
assert Role.count() == 2
assert UserRole.count() == 1
}
}
在上述的BootStrap.groovy中需要注意一些事情:
· 本例中没有使用传统的GORMmany-to-many 映射User<->Role 关系; 插入了一个映射连接表UserRole类。 当多个用户有一个或多个共同的角色时,这样做对性能的优化比较明显。
· 我们显式刷新创建,因为 BootStrap 没有在事务和OpenSessionInView中运行。
8.编辑grails-app/controllers/SecureController.groovy 倒入注解类并应用注解限制访问。
package com.testapp
import grails.plugins.springsecurity.Secured
class SecureController {
@Secured(['ROLE_ADMIN'])
def index = {
render 'Secure access only'
}
}
或者
package com.testapp
import grails.plugins.springsecurity.Secured
@Secured(['ROLE_ADMIN'])
class SecureController {
def index = {
render 'Secure access only'
}
}
你可以对控制器标注,也可以对其中的方法进行标注。在这里你只有一个方法,所以标注在哪里都可以。
9. 再次运行 grails run-app again 并导航到http://localhost:8080/bookstore/secure。
这一次,你可能会提前看到登录页面,用测试用户的用户名和密码登录,你随后可能会重新看到secure页面。
10. 测试Remember Me 功能
选中Remember Me 复选框,进入你测试的secure页面,关闭浏览器再重新打开它。再次导航到secure 页面。因为有一个cookie 被保存,你可能不需要再次登录。在任何时候要退出请导航到http://localhost:8080/bookstore/logout。
11.可选,为user和role创建一个创建CRUD UI 。
运行grailsgenerate-all 生成控制器和视图:
$ grails generate-all com.testapp.User
$ grails generate-all com.testapp.Role
用户类处理密码加密,对生成的控制器要求没有发生变化。