2012-08-09 97 views
6

我有以下代码:如何将多个方法添加到多重路线的方法中?

$r->find('user')->via('post')->over(authenticated => 1); 

鉴于路线我能得到通过认证检查 即使用Mojolicious ::插件::验证设置用户路径。

我想添加另一个'over'到该路线。

$r->find('user')->via('post')->over(authenticated => 1)->over(access => 1); 

虽然这看起来会覆盖已验证的'over'。

我想分手的路线与名称类似:

my $auth = $r->route('/')->over(authenticated => 1) 
    ->name('Authenticated Route'); 

$access = $auth->route('/user')->over(access => 1)->name('USER_ACCESS'); 

这并没有在所有的工作虽然。 'over'都没有被访问。

我的路由类似于/ user,/ item,使用MojoX :: JSON :: RPC :: Service设置。 所以,我没有像/ user /:id这样的东西来设置子路由(不太确定) 所有路由都是/ user,通过参数发送。

我有像一个条件:

$r->add_condition(
    access => sub { 
     # do some stuff 
    }, 
); 

即在$ R- '访问'>路线( '/用户') - >过(存取=> 1);

总之,使用航线时,做工精细:

$r->find('user')->via('post')->over(authenticated => 1); 

但我无法添加第二个途径。

那么,我在设置这些具有多个条件的路线时缺少什么? 是否可以向单个路由/路由名称添加多个条件?

+0

我注意到我在实施RBAC的同样的事情。我希望获得基于特权的访问授权,以表现得像树,这意味着链接。没有解决。我想这就是为什么他们给了我们桥梁。 :) – DavidO 2012-08-17 03:40:03

+1

我的问题是,我有一个'add_condition'路由修饰符中的路由,如上面的代码所示。所以,我无法与他们建立联系。我想我可以将这个条件作为一个函数移动到一个模块中,并使用一个桥。事实上,我把它放在了一个before_dispatch挂钩中。 – jmcneirney 2012-08-17 17:17:48

回答

2

你可以只在本次测试使用over两个条件,如:

use Mojolicious::Lite; 

# dummy conditions storing their name and argument in the stash 
for my $name (qw(foo bar)) { 
    app->routes->add_condition($name => sub { 
     my ($route, $controller, $to, @args) = @_; 
     $controller->stash($name => $args[0]); 
    }); 
} 

# simple foo and bar dump action 
sub dump { 
    my $self = shift; 
    $self->render_text(join ' ' => map {$self->stash($_)} qw(foo bar)); 
} 

# traditional route with multiple 'over' 
app->routes->get('/frst')->over(foo => 'yo', bar => 'works')->to(cb => \&dump); 

# lite route with multiple 'over' 
get '/scnd' => (foo => 'hey', bar => 'cool') => \&dump; 

# test the lite app above 
use Test::More tests => 4; 
use Test::Mojo; 

my $t = Test::Mojo->new; 

# test first route 
$t->get_ok('/frst')->content_is('yo works'); 
$t->get_ok('/scnd')->content_is('hey cool'); 

__END__ 
1..4 
ok 1 - get /frst 
ok 2 - exact match for content 
ok 3 - get /scnd 
ok 4 - exact match for content 

上的Perl 5.12.1做工精细这里Mojolicious 3.38 - @DavidO是对的,也许桥可以更好地完成这项工作。:)

0

在我来说,我使用两种方法under

$r = $app->routes; 
$guest = $r->under->to('auth#check_level'); 
$user = $r->under->to('auth#check_level', { required_level => 100 }); 
$admin = $r->under->to('auth#check_level', { required_level => 200 }); 

$guest->get('/')->to('main#index'); 
$user->get('/user')->to('user#show'); 
$super_admin = $admin->under->to('manage#check_level', { super_admin => 100 }); 
$super_admin->get('/delete_everything')->to('system#shutdown'); 

在这个例子中,当任何路由匹配一些under将被称为

'/' -> auth#check_level -> main_index 
'/user' -> auth#check_level { required_level => 100 } -> 'user#show' 
'/delete_everything' -> auth#check_level { required_level => 200 } -> 'manage#check_level', { super_admin => 100 } -> 'system#shutdown' 

您可以用指定action之前看您的controller将会运行另一个动作:auth#check_levelmanage#check_level

在每一个这些额外的动作,你只是比较stash->{ required_level }session->{ required_level }您设置当授权用户

package YourApp::Controller::Manage; 

sub check_level { 
    my $self = shift; 

    my $user_have = $self->session->{ required_level }; 
    my $we_require = $self->stash->{ required_level }; 
    # 'system#shutdown' will be called if user has required level 
    return 1 if $user_have >= $we_require; 


    $self->redirect_to('/you_have_no_access_rights'); 
    return 0; #This route will not match. 'system#shutdown' will not be called 
} 

PS我当然可以使用cb或只是CODEREF被“关闭同”到控制器的动作:

$r->under({ cb => \&YourApp::Controller::auth::check_level }); 
$r->under(\&YourApp::Controller::auth::check_level); # "same" 

但我更喜欢->to('controller#action')语法。它看起来好多了

0

如果我们使用这个黑客怎么办?

$r->add_condition(
     chain => sub { 
      my ($route, $controller, $captures, $conditions) = @_; 

      my $routes = $route; 
      while (not $routes->isa('Mojolicious::Routes')) { 
       $routes = $routes->parent; 
      } 

      for my $c (@$conditions) { 
       my $sub = $routes->conditions->{$c}; 
       return 0 unless $sub->($route, $controller, $captures); 
      } 

      return 1; 
     }, 
    ); 

    ... 
$r->get('/')->over(chain => ['condition1', 'condition2'])->to(cb => \&foo)->name('bar'); 
相关问题