我目前正在将CGI应用程序迁移到Dancer2。我以前使用过一种使用MySQL的“手工构建”身份验证机制,并使用带有属性email、password和state的用户表。state指示帐户是active还是locked。locked意味着帐户被禁用(逻辑上被删除)。
我还有表roles和user_roles来实现我的两个角色:管理和用户。
每件事都像一种魅力,只有一个例外:
使用我以前的“手工制作”机制,我能够锁定用户,即在逻辑上删除用户而不将他们从数据库中删除。只有当电子邮件和hash_of(密码)匹配并且帐户未被锁定时,登录才会成功。
如何用Dancer2::Plugin::Auth::Extensible和Dancer2::Plugin::Auth::Extensible::Provider::Database实现这一点?
我希望钩子after_authenticate_user能够返回true或false来覆盖authenticate_user的结果,但事实并非如此。至少,它没有记录在案。
我想到的一件事是有一个额外的角色active,然后--对于每一条路线-- require_role active而不是require_login。
因此,我的问题是:如何使Dancer2::Plugin::Auth::Extensible只考虑active用户?
发布于 2017-10-15 00:26:23
博罗丁创建视图并将其用作用户表。我做了一些测试,可以说这确实是实现这一目标的最简单的方法。
警告:由于视图的性质,这使得应用程序无法修改或添加用户!
考虑下面的Dancer2应用程序。我从dancer2创建脚本开始。
$ dancer2 gen -a Foo
$ cd Foo我创建了以下简单的sqlite数据库。
$ echo "
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(32) NOT NULL UNIQUE,
password VARCHAR(40) NOT NULL,
disabled TIMESTAMP NULL
);
CREATE VIEW active_users (id, username, password) AS
SELECT id, username, password FROM users WHERE disabled IS NULL;
INSERT INTO users ( username, password, disabled )
VALUES ( 'foo', 'test', null),
( 'bar', 'test', '2017-10-01 10:10:10');
" | sqlite3 foo.sqlite只有一个包含插件建议的默认列的users表,加上一个列disabled,可以是NULL,也可以是时间戳。我认为用残疾人来说明比用活动更容易。
然后,我对lib/Foo.pm做了以下更改。所有这些基本上都来自于Dancer2 2::Plugin::Auth::可扩展和Dancer2::Plugin::Auth::Extensible::Provider::Database的文档。
package Foo;
use Dancer2;
use Dancer2::Plugin::Database;
use Dancer2::Plugin::Auth::Extensible;
our $VERSION = '0.1';
get '/' => sub {
template 'index' => { 'title' => 'Foo' };
};
get '/users' => require_login sub {
my $user = logged_in_user;
return "Hi there, $user->{username}";
};
true;接下来,插件需要进入配置。编辑config.yml并将其替换为以下内容。
appname: "Foo"
layout: "main"
charset: "UTF-8"
template: "simple"
engines:
session:
Simple:
cookie_name: testapp.session
# this part is interesting
plugins:
Auth::Extensible:
realms:
users:
provider: 'Database'
############### here we set the view
users_table: 'active_users'
Database:
driver: 'SQLite'
database: 'foo.sqlite'
on_connect_do: ['PRAGMA foreign_keys = ON']
dbi_params:
PrintError: 0
RaiseError: 1现在我们都准备好尝试了。
$ plackup bin/app.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/在浏览器中访问http://localhost:5000/users。您将看到默认的登录表单。

输入foo和test。这应该是可行的,您应该可以看到/users路由。(或者不是,在我的例子中,重定向似乎被破坏了.)。

现在转到http://localhost:5000/logout,去掉foo的cookie,然后再打开http://localhost:5000/users。这一次,输入bar和test。
您将看到登录不起作用。

若要进行反测试,请替换config.yml中的config.yml并重新启动应用程序。
# config.yml
users_table: 'users'现在,用户foo将能够登录。
该方法不仅易于实现,而且应该是性能最高的方法,因为数据库处理了所有的逻辑(并且很可能已经缓存了它)。
您的应用程序,特别是身份验证插件,根本不需要知道活动字段或禁用字段的存在。他们不需要关心。东西只会起作用。
发布于 2017-10-14 16:47:49
您可以子类Dancer2::Plugin::Auth::Extensible::Provider::Database并包装get_user_details方法,以检查用户是否处于活动状态。
考虑我使用在我的另一个回答中的同一个应用程序。添加以下类。
package Provider::Database::ActiveOnly;
use Moo;
extends 'Dancer2::Plugin::Auth::Extensible::Provider::Database';
around 'get_user_details' => sub {
my $orig = shift;
my $self = shift;
# do nothing if we there was no user
my $user = $self->$orig(@_) or return;
# do nothing if the user is disabled
return if $user->{disabled};
return $user;
};
1;代码很简单。在查找用户之后,我们就有了用户数据,因此我们可以检查disabled列。如果其中有任何内容,则禁用该用户,然后我们中止。
您还需要对config.yml进行以下更改。
# config.yml
plugins:
Auth::Extensible:
realms:
users:
provider: 'Provider::Database::ActiveOnly'
users_table: 'users'现在,应用程序的行为应该与另一个答案完全一样。
要理解这一工作的原因,我们需要查看源代码。身份验证在authenticate_user中进行。最初我认为这是应该替换的,但是这个解决方案更聪明,因为我们只需要获取一次用户数据。
authenticate_user方法获取用户数据。与方法,因此我们可以挂在那里。我们的包装器将透明地注入用户的积极性检查,而其他代码甚至不知道有什么不同。
不活动的用户不会出现在任何与Plugin::Auth::可扩展的交互中。
https://stackoverflow.com/questions/46746864
复制相似问题