NEO

蜀道难,难于上青天!

导航

20130115-使用Grails Shiro Plugin实现身份验证01

Posted on 2013-01-15 13:20  页面载入出错  阅读(2395)  评论(2编辑  收藏  举报

目标

  • 尽可能简单的使用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

http://localhost:8080/shiro-example/home/admin : admin