SpringSrcureCode在grails中实现用户--角色--权限的管理

项目小组最近对原系统角色权限的管理进行重构,我使用Grails的插件SpringSecureCode来实现了用户--角色--权限的管理,即:用户可以关联多了角色,一个角色可以拥有多个权限。具体实现步骤如下:
一.  安装插件,执行插件的脚本建立管理内容
1.在cdm中打开项目目录,在项目下执行下面两条命:
$ grails install-plugin spring-security-core
$ grails s2-quickstart com.testapp UserDomain  RoleDomain

此时grails-app下domain views controllers建立了对应的MVC内容.

其中第一条命令是安装spring-security-core插件;第二条命令是建立用户与权限的实体."s2-quickstart"是安装插件后新增的命令,插件没有安装成功时,会提示无法识别"s2-quickstart";

com.testapp 是存放实体domain的包名,UserDomain RoleDomain可以根据项目需要自己命名

第一条命令的截图:

SpringSrcureCode在grails中实现用户--角色--权限的管理_第1张图片

第二条命令截图:User Role 这两个实体是测试用的实体名称,推荐大家使用StaffMember 和Authority 这两个名称,因为user和role 在某些地方是关键字。

SpringSrcureCode在grails中实现用户--角色--权限的管理_第2张图片

二.新增Role角色配置用户与角色 权限的关联

1.配置前先查看各个实体字段的含义吧:(现在把配置后完整的代码和注释罗列出来)

1.)用户

package xbudget

/**
* 用户实体类 --执行 s2-quickstart xbudget StaffMember Authority 自动生成后改动
*/
class StaffMember {
def springSecurityService
String username //登录的用户名
String password //登录密码,以密文形式存放
boolean enabled //用户是否启用 ,默认不启用
boolean accountExpired // 登录账号是否过期,默认不过期
boolean accountLocked //登录账号 是否锁定,默认不锁定
boolean passwordExpired //登录密码是否过期,默认不过期
// 下面是据项目自己填的
String realname
Department department
String lastLoginIp
Date lastLoginTime
String type
static hasMany = [role:Roles,btsm: BenchmarkingTeamStaffMember]//多个角色(改造新增Role角色后,一个用户关联多个角色),BenchmarkingTeamStaffMember是项目需要添加的,不在权限范畴
static constraints = {
username blank: false, unique: true
password blank: false
btsm nullable:true
role nullable: true
type nullable: true
lastLoginTime nullable: true
lastLoginIp nullable: true
department nullable: true
realname nullable: true
}
static mapping = {
password column: '`password`'
}
Set<Authority> getAuthorities() { //得到用户的所有权限列表
StaffMemberAuthority.findAllByStaffMember(this).collect { it.authority } as Set
}
def beforeInsert() { //新增用户时,保存到数据库前自动对密码加密
encodePassword()
}
def beforeUpdate() { //新增用户时,保存到数据库前自动对密码加密
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() { //密码加密方法
// password = springSecurityService.encodePassword(password) //默认加密方法
password = springSecurityService.encodePassword(password,username) //推荐使用的加密方法
}

}

2.)角色

package xbudget

/**
* 角色 自己新增
*/
class Roles {
String name; //角色名称
String remark//描述
/** 创建时间 */
Date dateCreated//创建时间
/** 最后更新的时间 */
Date lastUpdated//最后更新的时间
static belongsTo = StaffMember
static hasMany = [staffMember:StaffMember,rolesAuthority:RolesAuthority]//多个权限
static constraints = {
remark(nullable: true)
name unique: true
}
String toString()
{
"{$name}"
}

}

3.)权限

package xbudget

/**
* 权限 --执行 s2-quickstart xbudget StaffMember Authority 自动生成后改动
*/
class Authority {
String authority //权限名称
String remark;//权限说明
static hasMany=[rolesAuthority:RolesAuthority] //改造新增Role(角色)后与 权限与角色是多对多的关系,
// 新增一个 RolesAuthority 中间关联实体,便于管理权限与角色的关联
static mapping = {
//cache true
}
static constraints = {
authority blank: false, unique: true
remark nullable: true
}

}

4.)权限角色 关联的中间表

package xbudget

/**
* 权限角色 关联的中间表 --新增
*/
class RolesAuthority implements Serializable {
static belongsTo = [roles:Roles,authority:Authority]
static constraints = {
}
static mapping = {
id composite: ['roles', 'authority']
version false
}
boolean equals(other) {
if (!(other instanceof RolesAuthority)) {
return false
}
other.roles?.id == roles?.id &&
other.authority?.id == authority?.id
}
static RolesAuthority get(long rolesId, long authorityId) { //在control中使用RolesAuthority.get(rolesId,authorityId) 就能得到实体
find 'from RolesAuthority where roles.id=:rolesId and authority.id=:authorityId',
[rolesId: rolesId, authorityId: authorityId]
}
static RolesAuthority create(Roles roles, Authority authority, boolean flush = false) { //在control中使用RolesAuthority.create(roles,authority) 就能创建实体
new RolesAuthority(roles: roles, authority: authority).save(flush: flush, insert: true)
}
static boolean remove(Roles roles, Authority authority, boolean flush = false) { // 在control中使用RolesAuthority.remove(roles,authority) 就能创建实体
RolesAuthority instance = RolesAuthority.findByRolesAndAuthority(roles, authority)
if (!instance) {
return false
}
instance.delete(flush: flush)
true
}
static void removeAll(Roles roles) {
executeUpdate 'DELETE FROM RolesAuthority WHERE roles=:roles', [roles: roles]
}
static void removeAll(Authority authority) {
executeUpdate 'DELETE FROM RolesAuthority WHERE authority=:authority', [authority: authority]
}

}

5.用户与权限 关联表

package xbudget

/**
* 用户权限 关联表----执行 s2-quickstart xbudget StaffMember Authority 自动生成 没有修改
*/
import org.apache.commons.lang.builder.HashCodeBuilder
class StaffMemberAuthority implements Serializable {
StaffMember staffMember
Authority authority
boolean equals(other) {
if (!(other instanceof StaffMemberAuthority)) {
return false
}
other.staffMember?.id == staffMember?.id &&
other.authority?.id == authority?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (staffMember) builder.append(staffMember.id)
if (authority) builder.append(authority.id)
builder.toHashCode()
}
static StaffMemberAuthority get(long userId, long authorityId) {
find 'from StaffMemberAuthority where staffMember.id=:userId and authority.id=:authorityId',
[userId: userId, authorityId: authorityId]
}
static StaffMemberAuthority create(StaffMember staffMember, Authority authority, boolean flush = false) {
new StaffMemberAuthority(staffMember: staffMember, authority: authority).save(flush: flush, insert: true)
}
static boolean remove(StaffMember staffMember, Authority authority, boolean flush = false) {
StaffMemberAuthority instance = StaffMemberAuthority.findByStaffMemberAndAuthority(staffMember, authority)
if (!instance) {
return false
}
instance.delete(flush: flush)
true
}
static void removeAll(StaffMember staffMember) {
executeUpdate 'DELETE FROM StaffMemberAuthority WHERE staffMember=:staffMember', [staffMember: staffMember]
}
static void removeAll(Authority authority) {
executeUpdate 'DELETE FROM StaffMemberAuthority WHERE authority=:authority', [authority: authority]
}
static mapping = {
id composite: ['authority', 'staffMember']
version false
}

}

实体改动总结: 总的来说就是添加一个Role实体,把Role与用户和权限关联起来;为了让角色与权限管理方便 添加了一个中间表.

2.Config.groovy含义和修改:

// Added by the Spring Security Core plugin: //执行 s2-quickstart xbudget StaffMember Authority 自动生成后

grails.plugins.springsecurity.userLookup.userDomainClassName = 'xbudget.StaffMember' //用户实体类,可以指向自定义的用户实体
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'xbudget.StaffMemberAuthority' //用户与权限关联实体类,可以指向自定义的关联实体

grails.plugins.springsecurity.authority.className = 'xbudget.Authority' //权限实体类,可以指向自定义的权限实体

//自己添加下面的

grails.plugins.springsecurity.apf.filterProcessesUrl = '/login_check' //登录验证的路径,前台把用户名和密码提交到这个路径 ,默认是j_spring_security_check

grails.plugins.springsecurity.apf.usernameParameter = 'username' //前台提交用户名 时用到的参数名称,可以自定义,与前台一致即可
grails.plugins.springsecurity.apf.passwordParameter = 'password' //前台提交密码 时用到的参数名称,可以自定义,与前台一致即可

grails.plugins.springsecurity.logout.filterProcessesUrl = '/logout' //退出验证的路径, 前台要与此一致

三.书写后台现实用户关联角色,角色关联权限

1.实现思路:

SpringSrcureCode插件已经集成了用户与权限的直接关联,用户与权限的关联信息由实体StaffMemberAuthority 体现.系统登录成功后,会读取StaffMemberAuthority 对应表中该用户所有权限.

现在我们新加入了角色,需要做的工作有:角色与权限的关联,用户与角色的关联.但是由于插件只会读取StaffMemberAuthority 对应表中该用户所有权限;所以我们在实现用户与角色的关联时,要把该角色关联的权限与用户直接关联,也就是用户分配角色的时候,一方面更新用户与角色的关联(staffMember.addToRole(role)),另外也要更新StaffMemberAuthority 对应表中用户与权限的关联(StaffMemberAuthority .create(StaffMember staffMember, Authority authority, boolean flush = false));同理更新角色与权限的关联时也要更新StaffMemberAuthority 对应表.

2.实现源码:(略)

四.权限的注入(权限的使用):

1.自定义权限

默认提供的权限比较的少:ROLE_USER,ROLE_ADMIN ,所以我们要自定义权限,名称自己规定.

2.程序中使用@Secured标注安全,可以对整个控制器和方法标注

举例:

@Secured(["hasRole('P_ADMIN')"])

def admin = { //P_ADMIN, ROLE_ADMIN, ROLE_USER
render "admin Visit Sucess"

}

对于自定义的权限使用@Secured(["hasRole('name1')"])或@Secured(["hasAnyRole('[name1,name2]')])对于默认提供的权限可以使用 @Secured(['ROLE_ADMIN']);

@Secured可以对整个控制器控制

举例:

@Secured(['ROLE_ADMIN'])

class TestController {

def springSecurityService
def index = {
render "ROLE_ADMIN Visit Sucess"

}

}

3.把权限名称与用户关联一起 写在StaffMemberAuthority 对应表中.

写入后,用户登录系统后,用户就可以访问关联权限的控制器或方法了.对于没有关联的权限,系统会提示权限不足.

举例:

@Secured(['ROLE_ADMIN'])

class TestController {

def springSecurityService
def index = {
render "ROLE_ADMIN Visit Sucess"

}

}

用户关联了权限名为'ROLE_ADMIN'的权限,那么登陆后访问TestController 时就可以正常访问,如果没有关联,就会提示权限不足.

4.扩展使用:

以上只是提供了用户--角色--权限的三层关联关系,具体怎么对权限划分,那一个权限包括些control或那些方法(闭包),一个闭包有哪些权限,这是需要根据项目权限设计方案,对上面权限进行设定.暂时不提供现在对标项目的设计方案.

原文:http://my.oschina.net/u/189572/blog/40705

你可能感兴趣的:(加密,String,equals,delete,grails,constraints)