您的位置:首页 > 编程语言 > Java开发

grails 之 Spring Security Core Plugin 使用

2012-09-01 10:33 573 查看
Spring Security Core Plugin是Spring的一个强大的权限控制插件,Secure your applications using the powerful Spring Security library quickly and easily

官方插件地址:http://www.grails.org/plugin/spring-security-core

官方使用手册:http://grails-plugins.github.com/grails-spring-security-core/docs/manual/

在grails项目中插入Spring Security Core Plugin。

grails install-plugin spring-security-core
如果你使用intellij IDEA的话就可以很简单的插入插件了,如下图





这时系统就会自动插入插件,插入插件后就可开始配置使用spring security Core插件了

详细使用如下,原文地址:http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/23%20Tutorials.html#23.1%20Using%20Controller%20Annotations%20to%20Secure%20URLs


23 Tutorials


23.1 Using Controller Annotations to Secure URLs


1. Create your Grails application.

$ grails create-app bookstore
$ cd bookstore



2. Install the plugin.

$ grails install-plugin spring-security-core



3. Create the User and Role domain classes.

$ grails s2-quickstart com.testapp User Role


You can choose your names for your domain classes and package; these are just examples.

Depending on your database, some domain class names might not be valid, especially those relating to security. Before you create names like "User" or "Group", make sure they are not reserved keywords in your database.

The script creates this User class:

package com.testapppackage testclass 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)
}
}


Earlier versions of the plugin didn't include password encryption logic in the domain class, but it makes the code a lot cleaner.

and this Role class:

package com.testappclass Role {   String authority   static mapping = {
cache true
}   static constraints = {
authority blank: false, unique: true
}
}


and a domain class that maps the many-to-many join class,
UserRole
:

package com.testappimport org.apache.commons.lang.builder.HashCodeBuilderclass UserRole implements Serializable {   User user
Role role   boolean equals(other) {
if (!(other instanceof UserRole)) {
return false
}      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 where user.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)
}   static boolean remove(User user, Role role, boolean flush = false) {
UserRole instance = UserRole.findByUserAndRole(user, role)
if (!instance) {
return false
}      instance.delete(flush: flush)
true
}   static void removeAll(User user) {
executeUpdate 'DELETE FROM UserRole WHERE user=:user', [user: user]
}   static mapping = {
id composite: ['role', 'user']
version false
}
}


It also creates some UI controllers and GSPs:

grails-app/controllers/LoginController.groovy

grails-app/controllers/LogoutController.groovy

grails-app/views/auth.gsp

grails-app/views/denied.gsp


The script has edited
grails-app/conf/Config.groovy
and added the configuration for your domain classes. Make sure that the changes are correct.

These generated files are not part of the plugin - these are your application files. They are examples to get you started, so you can edit them as you please. They contain the minimum needed for the plugin.

The plugin has no support for CRUD actions and GSPs for your domain classes; the
spring-security-ui
plugin will supply a UI for those. So for now you will create roles and users in
grails-app/conf/BootStrap.groovy
.
(See step 7.)


4. Create a controller that will be restricted by role.

$ grails create-controller com.testapp.Secure


This command creates
grails-app/controllers/com/testapp/ SecureController.groovy
. Add some output so you can verify that things are working:

package com.testappclass SecureController {
def index = {
render 'Secure access only'
}
}



5. Start the server.

$ grails run-app



6. Before you secure the page, navigate to http://localhost:8080/bookstore/secure to verify that you can see the page without being logged
in.


7. Shut down the app (using CTRL-C) and edit grails-app/conf/BootStrap.groovy to add the security objects that you need.

import com.testapp.Role
import com.testapp.User
import com.testapp.UserRoleclass 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
}
}


Some things to note about the preceding
BootStrap.groovy
:

The example does not use a traditional GORM many-to-many mapping for the User<->Role relationship; instead you are mapping the join table with the
UserRole
class.
This performance optimization helps significantly when many users have one or more common roles.
We explicitly flushed the creates because
BootStrap
does not run in a transaction or OpenSessionInView.


8. Edit grails-app/controllers/SecureController.groovy to import the annotation class and apply the annotation to restrict access.

package com.testappimport grails.plugins.springsecurity.Securedclass SecureController {   @Secured(['ROLE_ADMIN'])
def index = {
render 'Secure access only'
}
}


You can annotate the entire controller or individual actions. In this case you have only one action, so you can do either.


9. Run grails run-app again and navigate to http://localhost:8080/bookstore/secure.

This time, you should be presented with the login page. Log in with the username and password you used for the test user, and you should again be able to see the secure page.


10. Test the Remember Me functionality.

Check the checkbox, and once you've tested the secure page, close your browser and reopen it. Navigate again the the secure page. Because a is cookie stored, you should not need to log in again. Logout at any time by navigating to http://localhost:8080/bookstore/logout.


11. Optionally, create a CRUD UI to work with users and roles.


Run grails generate-all for the domain classes:


$ grails generate-all com.testapp.User


$ grails generate-all com.testapp.Role


Since the User domain class handles password encryption, there are no changes required in the generated controllers.


23.2 Migration From the Acegi Plugin

In this tutorial we'll discuss the general steps required to migrate from the Acegi plugin to the Spring Security Core plugin. A lot of the material here comes from an
email that Lubos Pochman sent to the User mailing list documenting the steps he took to upgrade from the Acegi plugin.

This isn't a standard step-by-step tutorial since every application is different and the steps required will vary from project to project. Instead these are guidelines and things to keep in mind. You should also readSection
2 and Section 3.

The first thing to do is uninstall the Acegi plugin

$ grails uninstall-plugin acegi


and install Spring Security Core

$ grails install-plugin spring-security-core


If this were a new project the next step would be to run the s2-quickstart script
but you wouldn't do this for an existing project where you already have a User and Role class, so it's a good idea to work through thebookstore
tutorial and use the files generated in that project. The files that the script generates are

grails-app/domain/com/testapp/User.groovy

grails-app/domain/com/testapp/Role.groovy

grails-app/domain/com/testapp/UserRole.groovy

grails-app/controllers/LoginController.groovy

grails-app/controllers/LogoutController.groovy

grails-app/views/login/auth.gsp

grails-app/views/login/denied.gsp


Migrate any changes you made in
LoginController.groovy
,
LogoutController.groovy
,
auth.gsp
and
denied.gsp
,
and overwrite your files with those. Do the same for
User.groovy
and
Role.groovy
, and move
UserRole.groovy
into
your project.


User and Role UI

You can use the standard Grails
generate-all
script to create a UI to manage Users and Roles as described in the previous tutorial, or for a more complete solution use the Spring
Security UI plugin.


authenticateService

The utility service in Spring Security Core is
SpringSecurityService
, so you need to replace
def authenticateService
with
def
springSecurityService
. Many of the methods have the same names and signatures but there are some differences:

principal()
was renamed to
getPrincipal()

ifAllGranted()
,
ifNotGranted()
, and
ifAnyGranted()
were
removed; use
org.codehaus.groovy.grails.plugins.springsecurity. SpringSecurityUtils.ifAllGranted()
,
ifNotGranted()
,
and
ifAnyGranted()
instead
getSecurityConfig()
was removed, use
SpringSecurityUtils.getSecurityConfig()
instead

One significant change between the plugins is that the
UserDetails
implementation (
GrailsUser
) no longer
has a reference to the domain class instance. This was intended to make it easy to access User class data that's not available in the
Principal
but it has frustrating side effects
due to being a disconnected Hibernate object. Instead
GrailsUser
stores the user's id so you can conveniently retrieve the instance when needed. So instead of

def user = authenticateService.userDomain()
user = User.get(user.id)


use this instead:

def user = User.get(springSecurityService.principal.id)



Role granting

The Acegi plugin uses a standard Grails many-to-many relationship (i.e. using
hasMany
and
belongsTo
)
between User and Role but this will have performance problems if you have many users. Spring Security Core also uses a many-to-many relationship but maps the join table as a domain class instead of using collections. In the Acegi plugin you would grant a role
to a user using

Role role = …
User user = …
role.addToPeople(user)


and remove the grant with

Role role = …
User user = …
role.removeFromPeople(user)


In Spring Security Core you use the helper methods in
UserRole


Role role = …
User user = …
UserRole.create user, role


and

Role role = …
User user = …
UserRole.remove user, role


which directly insert or delete rows in the User/Role join table.


SecurityConfig.groovy

Configuration settings are now stored in
grails-app/conf/Config.groovy
along with the rest of the application configuration. The primary motiviation for this change is to easily support
environment-specific security settings. Migrate settings from
SecurityConfig.groovy
to
Config.groovy
(see this
summary for the new names.

In particular it's important that the following properties be configured (replace class and package names to match your domain classes):

grails. plugins. springsecurity. userLookup. userDomainClassName =
'com.yourcompany.yourapp.User'
grails. plugins. springsecurity. userLookup. authorityJoinClassName =
'com.yourcompany.yourapp.UserRole'
grails. plugins. springsecurity. authority. className =
'com.yourcompany.yourapp.Role'


Delete
SecurityConfig.groovy
when you're finished.


Controller annotations

The
Secured
annotation changed from
org.codehaus.groovy.grails.plugins. springsecurity.Secured
to
grails.plugins.springsecurity.Secured
.
Consider using SpEL
expressions since they're a lot more powerful and expressive than simple role names.


Security tags

tag names now start with 'if' instead of 'is', and the
role
attribute changed to
roles
,
so for example change
<g:ifAnyGranted role='...'>
to
<sec:ifAnyGranted roles='...'>

use
<sec:username/>
instead of
<g:loggedInUserInfo(field:'username')}/>
-
use
<sec:loggedInUserInfo>
to render other
GrailsUser
attributes

在Grails项目的Config.groovy中配置如下配置

grails {
plugins {
springsecurity {
active = true
userLookup.userDomainClassName = "com.testapp.User"
authority.className = "com.testapp.Role"
}
}
}


到这一步,基础建设基本完成了,接下来可以开始建设对应的controller进行权限访问了。

对用的controller代码

LoginControoler

def auth = {
nocache response

if (isLoggedIn()) {
redirect uri: '/'
return
}

String view = 'auth'
String postUrl = "${request.contextPath}${SpringSecurityUtils.securityConfig.apf.filterProcessesUrl}"

render view: view, model: [postUrl: postUrl]
}


auth.gsp

<form action='${postUrl}' method='POST' id='loginForm' class='cssform'>
<p>
<label class="required" for="j_username">用户名:</label><br/>
<input type='text' class='text_' name='j_username' id='j_username' value='${request.remoteUser}'/>
</p>

<p>
<label class="required" for="j_password">密码:</label><br/>
<input type='password' class='text_' name='j_password' id='j_password'/>
</p>

<p> </p>

<p>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="100%"><input type="submit" value="登录"/></td>
</tr>
</table>
</p>
</form>


LoginOutControoler

def denied = {
// TODO  put any pre-logout code here
redirect(uri: '/j_spring_security_logout')
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: