使用情况
我花了很多功夫研究WordPress的认证系统。 两年前我接手WordPress的OpenID插件开发工作,去年五月又被Vidoop聘请来全职研究DiSo项目。 去年夏天,我应Matt Mullenweg的邀请在 WordPress 2008年的San Francisco 夏令营中讲述关于OAuth的问题。 你可以在我的 slidedeck看到,那时这仅仅是一个幻象…当时WordPress中还没有OAuth,尽管在产品计划书上已经列出这一规划。
Stephen Paul Weber写到,我们刚开发出一款OAuth插件,但直到几个月前我才有时间改进这款插件。 我们要解决的第一个使用问题就是XML-RPC,因此我开始与Joseph Scott合作。 如果给博客客户端(如MarsEdit或WordPress iPhone app)添加Oauth认证程序,客户端就可以直接与你的博客交流而不必用到你的WordPress密码了。
出现的问题
不久前我们终于解决了我对WordPress认证系统的最大埋怨——太“用户名/密码”化了。 如果忘记用户名或密码,认证程序的代码中过早跳出空白。 如果你的插件只需要验证用户名是否与LDAP中存储的密码一致,这就很容易了;事实证明一切运行良好。
问题是,虽然外界开发了大批认证系统(如SAML,OpenID,OAuth等),但它们都不符合用户名和密码的标准模式。 你可以到OpenID插件上看看一些更有趣的东西,它们都需要人为完成以便在不同版本的WordPress上运行。 尽管如此,在将OAuth代码连接到WordPress XML-RPC终点时,我们没有办法绕过这一步骤…我们不得不改变一些基本的设想。
这个额外要求也没有什么作用。 因为wp_authenticate()函数驻留在pluggable.php中,该函数承担WordPress认证的大部分工作,这样插件就有可能完全取代函数的功能并随意对用户进行认证了。 这个方法带来的问题是,很多认证机构在不检查请求的情况下无法辨别它们是否被调用。 取代wp_authenticate函数之后插件才发现它本不应该如此,但这时已经太晚了。 我们无法避免在回到wp_authenticate标准版本时遇到这个函数。 事实上pluggable.php中所有的函数都是这样。一个可行的解决方案是为每个函数创建包装器函数,这也是我最初所主张的。 但Peter Westwood想到一个更好的方法,可以采用一个已建成的模式,最后我们在新认证系统中采纳了他的意见。
解决方案
对这个方案的规划比实际编码要麻烦的多,但最终我们还是成功了,开发出的方案脱离了对“用户名”和“密码”模式的依赖,同时还兼容连接认证程序代码的现有插件。 WordPress 2.8 含有一个名为authenticate的新过滤器,它传递了三个参数: 一个混合值(可能是WP_User对象,WP_Error对象,或者空值),以及用户名和密码(其值都可以为空)。 这样所有的标准WordPress认证逻辑就被移入下面这两个执行过滤器的函数了,它们的优先级相对较低。
- wp_authenticate_username_password() (优先级为20)中包含用于标准“用户名”和“密码”验证的标准逻辑。 这仍被称为wp_authenticate_user过滤器,因此附着与该过滤器的插件仍然可以使用。 这个函数也执行对空用户名和密码的检查。
- Wp_authenticate-cookie() (优先级为30)只在用户通过wp_login.php进行验证时才被加入过滤器链,它主要对WordPress验证cookie进行常规检查。
以上两个函数都会对第一个传递的参数进行检查,如果它是有效的WP_User对象则立即停止。 这就允许插件以适当形式将其自身函数添加到可生成WP_User对象的过滤器链中。 WordPress也在适当的时候设置了认证程序的cookie,因此插件只需要负责认证用户并返回有效的WP_User对象。
那么,对插件来说这意味着什么呢? 当然,WordPress的OAuth插件尚未完工,但下面的函数已经相当接近最终版本了。 实际执行OAuth仍然需要更多代码,这仅仅是能使WordPress认证程序连接生效的代码段。 请注意,认证程序钩子(hook)中的用户名和密码参数对本函数不产生影响…其他插件可能会用到这些参数。
add_filter('authenticate', 'oauth_authenticate');
/**
* If the current request was signed using a valid OAuth access token, verify
* the request and return the associated user.
*
* @param WP_User|WP_Error|null $user authenticated user
* @return WP_User|WP_Error|null OAuth authenticated user, if request was signed
*/
function oauth_authenticate($user) {
if (Auth_OAuth_Signer::requestIsSigned()) {
$oauth_server = oauth_server();
$user_id = $oauth_server->verify();
if ($user_id !== false) {
$user = new WP_User($user_id);
}
}return $user;
}
写给插件开发者
如果你现在正要连接WordPress的认证系统,或者说你要为wp_authenticate()提供自定义工具,请先了解新认证程序的钩子(hook)。 如果你依赖于wp_authenticate hook,也请先了解新的hook是否能帮上你的忙。 我们现在已经把wp_authenticate hook安排妥当,但我坚信它已经不再是必需,也许新版本中我们就不再看到它了。 也许你只使用wp_authenticate_user hook,那么你可能是个高手,不过了解一下新事物也不是个坏主意。
在WordPress中使用会怎么样?
我们对WordPress XML-RPC代码又做了些附加更改,使它能够很好的适应新的认证程序,这样即使不做主要修改我们也可能将OAuth连接到WordPress。 事实上在WordPress的主版本中已经使用了基本的OAuth插件。但由于以下两个原因,我不打算将OAuth代码编入Wordpress 2.8中:
- OAuth程序库目前正处于不断变化中。 人们常用两个PHP程序库来为OAuth服务,这两个程序库各有长短。 我用 oauth-php community将这些程序库中的精华部分合并,生成一个纯净的新结构。 在 github上可以看到这种效果。 (这个程序库要求PHP5运行环境,而PHP5将对WordPress产生不良影响…怎样处理这一情况还是个问题)
- OAuth有可能成为与WordPress博客交互的第三方的重要部分,因此我希望我们的想法是正确的。 就个人而言,将代码先作为插件发布出去,并在相对受限的环境中得到一些实际经验,我会感觉轻松很多。 当我们完成以上事情,并对与WordPress(插件API,管理界面,数据库结构等)的连接感到满意时,我会举双手赞成OAuth成为WordPress的重要部分。
原文:Authentication in WordPress 2.8
分类:新闻资讯