grails 之 Spring Security Core Plugin 使用

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.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) } }

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.testapp

class 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.testapp

import org.apache.commons.lang.builder.HashCodeBuilder

class 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.testapp

class 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.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 } }

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.testapp

import grails.plugins.springsecurity.Secured

class 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.groovyLogoutController.groovyauth.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')
    }





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值