Chinaunix首页 | 论坛 | 博客
  • 博客访问: 385947
  • 博文数量: 69
  • 博客积分: 1984
  • 博客等级: 上尉
  • 技术积分: 953
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-28 00:43
个人简介

学无所长,一事无成

文章分类

全部博文(69)

文章存档

2015年(19)

2014年(14)

2013年(9)

2012年(17)

2010年(10)

我的朋友

分类:

2010-08-27 12:15:21

Catalyst::Manual::Tutorial::06_Authorization

学习笔记 (2010-8-27 星期五)-- 用户权限管理
 
文章来源:
 
概述:
 
本章会讲述基于角色的用户权限管理,描述了如何在 TT 模板及 controller action 中使用角色控制。前半部分将基本的权限管理原则;后半部分讲述如何将权限管理代码移入到 model 中,从而可以简化管理。
 
本章的例子程序可以从  一章中描述的地址找到。
 
 
本章学习基本的 catalyst 的权限管理知识。
 
 
编辑 lib/MyApp.pm ,添加 Authorization::Roles
 

# Load plugins
use Catalyst qw/
    -Debug
    ConfigLoader
    Static::Simple

    
    StackTrace
    
    Authentication
    Authorization::Roles
    
    Session
    Session::Store::FastMmap
    Session::State::Cookie
/;

同样修改 Makefile.PL ,添加:

requires 'Catalyst::Plugin::Authorization::Roles';


Add Role-Specific Logic to the "Book List" Template

编辑 root/src/books/list.tt2 ,底部添加:

...
<p>Hello [% c.user.username %], you have the following roles:</p>
<ul>
  [% # Dump list of roles -%]
  [% FOR role = c.user.roles %]<li>[% role %]</li>[% END %]
</ul>
<p>
[% # Add some simple role-specific logic to template %]
[% # Use $c->check_user_roles() to check authz -%]
[% IF c.check_user_roles('user') %]
  [% # Give normal users a link for 'logout' %]

  <a href="[% c.uri_for('/logout') %]">User Logout</a>
[% END %]
[% # Can also use $c->user->check_roles() to check authz -%]
[% IF c.check_user_roles('admin') %]
  [% # Give admin users a link for 'create' %]
  <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Admin Create</a>
[% END %]
</p>

Limit Books::add to 'admin' Users

通过 TT 模板简单控制浏览器,会导致一些安全问题,比如用户直接通过 url 调用 action ,我们接下来进行功能包裹,加强权限约束。

实例,我们约束 "formless create" 功能只能管理员使用,编辑 lib/MyApp/Controller/Books.pm 文件,修改 url_create : 

sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
    # In addition to self & context, get the title, rating & author_id args
    # from the URL. Note that Catalyst automatically puts extra information
    # after the "//
    my ($self, $c, $title, $rating, $author_id) = @_;
    # Check the user's roles

    if ($c->check_user_roles('admin')) {
        # Call create() on the book model object. Pass the table
        # columns/field values we want to set as hash values
        my $book = $c->model('DB::Book')->create({
                title => $title,
                rating => $rating
            });

        # Add a record to the join table for this book, mapping to
        # appropriate author
        $book->add_to_book_authors({author_id => $author_id});
        # Note: Above is a shortcut for this:
        # $book->create_related('book_authors', {author_id => $author_id});
        # Assign the Book object to the stash and set template
        $c->stash(book => $book,
                  template => 'books/create_done.tt2');
    } else {
        # Provide very simple feedback to the user.
        $c->response->body('Unauthorized!');
    }
}


我们简单的将程序逻辑放到 check_user_roles 的 if 语句中,如果用户没有权限,将得到信息"Unauthorized!"。

提示:如果你想保存原始的 url_create ,可以先复制,再使用 pod 语法 =begin=end 进行注释。

Try Out Authentication And Authorization

$ script/myapp_server.pl -r

访问 ,会进入到登录界面(如果已登录就退出)。使用用户名 test01、 test02,密码 mypass ,注意观察页面 "Book List" 下的 role 信息。

你是用 test01 就可以正常访问 "url_create" ,使用 test02 会看到验证失败信息。

ENABLE MODEL-BASED AUTHORIZATION

上述权限控制浅显易懂,可未免不够清晰简洁,扩展性也不好。大部分 MVC 框架的目标,都是要是 controller 和 view 尽可能的简洁,尽可能的将业务逻辑放入 model 当中。

举个例子,让我给 Books.pm 结果类添加一个方法,用来检查一个用户是否有权限删除一本书。编辑 lib/MyApp/Schema/Result/Book.pm ,添加如下方法(要添加在 "DO NOT MODIFY ..." 这一行下面):

sub delete_allowed_by {
    my ($self, $user) = @_;
    
    # Only allow delete if user has 'admin' role

    return $user->has_role('admin');
}

这里我们在 user object 上调用 has_role 方法,我们就可以将这个方法添加到结果类中。编辑 lib/MyApp/Schema/Result/User.pm ,添加如下方法(注意在 "DO NOT MODIFY ..." 后面):

use Perl6::Junction qw/any/;
sub has_role {
    my ($self, $role) = @_;
    # Does this user posses the required role?
    return any(map { $_->role } $self->roles) eq $role;
}

现在我们需要往 controller 里添加一些增强功能。编辑 lib/MyApp/Controller/Books.pm 文件,修改 delete 方法如下:

sub delete :Chained('object') :PathPart('delete') :Args(0) {
    my ($self, $c) = @_;
    # Check permissions
    $c->detach('/error_noperms')
        unless $c->stash->{object}->delete_allowed_by($c->user->get_object);
    # Use the book object saved by 'object' and delete it along
    # with related 'book_authors' entries
    $c->stash->{object}->delete;
    # Use 'flash' to save information across requests until it's read
    $c->flash->{status_msg} = "Book deleted";
    # Redirect the user back to the list page
    $c->response->redirect($c->uri_for($self->action_for('list')));
}

这里,如果用户缺少适当权限会 detach 到错误信息页面。这里需要添加 '/error_noperms' action ,编辑 lib/MyApp/Controller/Root.pm ,添加:

sub error_noperms :Chained('/') :PathPart('error_noperms') :Args(0) {
    my ($self, $c) = @_;
    $c->stash(template => 'error_noperms.tt2');
}

然后添加模板文件,编辑 root/src/error_noperms.tt2:

<span class="error">Permission Denied</span>

用 test01 登录,用 url_create 创建几本书:

现在,以 test01 登录,可以点击 "Delete" 删除书目,操作正常,并得到 "Book deleted" 信息。退出,用 test02 登录,执行同样动作,你会得到 "Permission Denied" 信息。说明权限控制生效了。

本章结束

 


 

阅读(1081) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~