目标
- 尽可能简单的使用Grails Shiro Plugin实现身份验证功能.
安装
- Grails版本:2.1.1
- 约定:在代码示例中,任何使用$开头,说明这是一个shell命令
1 $ grails create-app shiro-example 2 $ cd shiro-example
- shiro plugin最新的插件版本是1.1.4,可以使用grails install-plugin shiro安装,但是这里使用最新的快照版本。不需要用shell安装只需要在项目的BuildConfig.groovy中增加插件的引用即可
plugins { runtime ":hibernate:$grailsVersion" runtime ":jquery:1.8.3" runtime ":resources:1.1.6" runtime ":shiro:1.2.0-SNAPSHOT"
- 当我们修改了BuildConfig.groovy文件后,需要对系统进行重新编译,修改才能生效
$ grails compile
- 现在插件已经安装好了,下一步建立一个初步的脚手架,执行这个shell后,系统会帮我们生成一系列的脚手架文件,这个--prefix=[包路径]是可选项,如果使用包路径,不要忘记最后面的那个"."
$ grails shiro-quick-start --prefix=com.example. | Created file grails-app/domain/com/example/User.groovy | Created file grails-app/domain/com/example/Role.groovy | Created file grails-app/realms/com/example/DbRealm.groovy | Created file grails-app/controllers/com/example/AuthController.groovy | Created file grails-app/views/auth/login.gsp | Created file grails-app/conf/com/example/SecurityFilters.groovy
配置
Bootstrap.groovy
1 import com.example.Role 2 import com.example.User 3 4 class BootStrap { 5 6 def shiroSecurityService 7 8 def init = { servletContext -> 9 // Create the admin role 10 def adminRole = Role.findByName('ROLE_ADMIN') ?: 11 new Role(name: 'ROLE_ADMIN').save(flush: true, failOnError: true) 12 13 // Create the user role 14 def userRole = Role.findByName('ROLE_USER') ?: 15 new Role(name: 'ROLE_USER').save(flush: true, failOnError: true) 16 17 // Create an admin user 18 def adminUser = User.findByUsername('admin') ?: 19 new User(username: "admin", 20 passwordHash: shiroSecurityService.encodePassword('password')) 21 .save(flush: true, failOnError: true) 22 23 // Add roles to the admin user 24 assert adminUser.addToRoles(adminRole) 25 .addToRoles(userRole) 26 .save(flush: true, failOnError: true) 27 28 // Create an standard user 29 def standardUser = User.findByUsername('joe') ?: 30 new User(username: "joe", 31 passwordHash: shiroSecurityService.encodePassword('password')) 32 .save(flush: true, failOnError: true) 33 34 // Add role to the standard user 35 assert standardUser.addToRoles(userRole) 36 .save(flush: true, failOnError: true) 37 38 } 39 def destroy = { 40 } 41 }
- 在代码第6行,引入了shiro的安全服务,并使用服务的encodePassword方法进行加密
- 在代码第9到15行,新增admin和user两个角色
- 在代码第17到21行,新增一个账号为admin的用户,并对password进行加密
- 在代码第23到26行,给admin用户进行角色授权
- 在代码第28到36行,给user用户进行角色授权
运行测试一下效果
$grails run-app
or
$grails -Dserver.port=8888 run-app
登录http://localhost:8080/shiro-example,点com.example.AuthController控制器,系统弹出登录窗口,输入账号和密码后,系统返回主界面,什么都没发生过。这是因为我们没有需要验证的界面,下面再增加一点东西
- 新增一个控制器
$ grails create-controller com.example.Home
- 给这个控制器增加三个action
1 package com.example 2 3 class HomeController { 4 5 def index() { 6 render "这个页面不需要验证" 7 } 8 9 def secured() { 10 render "这个页面需要user角色才能访问" 11 } 12 13 def admin() { 14 render "这个页面需要admin角色才能访问" 15 } 16 }
- 正如我们看到的,我可以分别登陆不同的视图,特定的角色才能返回正常的结果
- 如果权限不够的用户登录到了相应页面,系统提示“You do not have permission to access this page”
- 如果我们现在运行,并访问,不管登录到index、secured还是admin,系统都会提示“You do not have permission to access this page”
现在,分别给不同的action进行授权,打开SecurityFilters.groovy,拷贝如下代码
1 package com.example 2 3 /** 4 * Generated by the Shiro plugin. This filters class protects all URLs 5 * via access control by convention. 6 */ 7 class SecurityFilters { 8 9 /** 10 * Array of controller/action combinations which will be skipped from authentication 11 * if the controller and action names match. The action value can also be '*' if it 12 * encompasses all actions within the controller. 13 */ 14 static nonAuthenticatedActions = [ 15 [controller: 'home', action: 'index'] 16 ] 17 18 /** 19 * Array of controller/action combinations that will be authenticated against the user's 20 * role. The map also includes the roles which the controller/action pair will match 21 * against. 22 */ 23 static authenticatedActions = [ 24 [controller: 'home', action: 'secured', roles: ['ROLE_ADMIN', 'ROLE_USER']], 25 [controller: 'home', action: 'admin', roles: ['ROLE_ADMIN']] 26 ] 27 28 def filters = { 29 30 all(controller: '*', action: '*') { 31 before = { 32 33 // Determine if the controller/action belongs is not to be authenticated 34 def needsAuth = !nonAuthenticatedActions.find { 35 (it.controller == controllerName) && 36 ((it.action == '*') || (it.action == actionName)) 37 } 38 39 if (needsAuth) { 40 41 // Get the map within the authenticated actions which pertain to the current 42 // controller and view. 43 def authRoles = authenticatedActions.find { 44 (it.controller == controllerName) && 45 ((it.action == '*') || (it.action == actionName)) 46 } 47 48 if (authRoles) { 49 50 // Perform the access control for each of the roles provided in the authRoles 51 accessControl { 52 authRoles.roles.each { roleName -> 53 role(roleName) 54 } 55 } 56 } 57 58 // Skip authentication if the authRoles was not found 59 else { 60 return true 61 } 62 } 63 64 // Skip authentication if no auth is needed 65 else { 66 return true 67 } 68 } 69 } 70 71 } 72 }
- 代码第14到16行,登记不需要授权的action
- 代码第23到26行,登记需要授权的action,并指定相应的角色
现在,大功告成,再使用不同的角色,访问不同的页面,应该可以得到不同的效果
http://localhost:8080/shiro-example/home/index : non
http://localhost:8080/shiro-example/home/secured : user,admin