WordPress 2.8中的认证系统
使用情况 我花了很多功夫研究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)中的用户名和密码参数对本函数不产生影响…其他插件可能会用到这些参数。 […]