Symfonyob娱乐下载 2.4新增功能:轻松自定义安全特性
警告:这篇文章是关于一个不受支持的Symfony版本。ob娱乐下载有些信息可能已经过时了。阅读最新的Symfony文档ob娱乐下载.
提供的
乔迪Boggiano
在# 6069.
那么,您听说过使用Symfony2安全层很复杂吗?ob娱乐下载我倾向于既同意又不同意。一方面,如果您的需求是“标准的”(用户存储在数据库中的表单身份验证、HTTP基本身份验证等等),那么设置安全性就像配置一些选项一样简单。
但另一方面,如果您想要一个自定义身份验证/授权/用户提供程序系统,事情就会变得有点复杂,因为您需要理解所有的概念以及需要如何连接所有内容。从Symfoob娱乐下载ny 2.4开始,由于引入了一些更简单的方法来定制安全层,而不需要创建一堆类,因此这个过程变得更容易了。在这篇文章中,我将描述如何编写一些常见的特性。
使用自定义用户提供程序
在开始深入研究新的自定义特性之前,让我们通过将用户凭证存储在平面文件中来简化事情。当然,大多数情况下,用户凭证存储在数据库中;Symfob娱乐下载ony提供了Doctrine和Propel的内置集成。
为了保持示例简单,让我们使用一个简单的JSON文件:
- {
- "foo": "37b51d194a7513e45b56f6524f2d51f2", "bob": "098f6bcd4621d373cade4e832627b4f6"
}
用户名是密钥,值是密码,用md5
函数来保持简单。
创建用户提供程序与实现一样简单ob娱乐下载
:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
使用ob娱乐下载\组件\安全\核心\用户\用户;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\核心\用户\用户界面;使用ob娱乐下载\组件\安全\核心\异常\UsernameNotFoundException;使用ob娱乐下载\组件\安全\核心\异常\UnsupportedUserException;类JsonUserProvider实现了UserProviderInterface{受保护的$用户;公共函数__construct(){$这->用户= json_decode(file_get_contents(“/道路/ / users.json”),真正的);}公共函数loadUserByUsername($用户名){如果(收取($这->用户($用户名))) {返回新用户($用户名,$这->用户($用户名),数组(“ROLE_USER”));}扔新UsernameNotFoundException (sprintf (“用户名“%s”不存在。”,$用户名));}公共函数refreshUser(用户界面$用户){如果(!$用户运算符用户){扔新UnsupportedUserException (sprintf (“不支持“%s”的实例。”get_class ($用户)));}返回$这->loadUserByUsername ($用户->getUsername ());}公共函数supportsClass($类){返回Sob娱乐下载ymfony的核心组件\ \安全\ \ \用户”= = =$类;}}
我们使用的是内置的用户
类来表示我们的用户。在你的配置中使用这个提供程序是很简单的:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
服务:json_user_provider:{类:JsonUserProvider}安全:提供者:json:id:json_user_provider防火墙:secured_area:模式:^ /管理供应商:json#……编码器:ob娱乐下载Symfony核心组件\ \安全\ \ \用户:算法:md5迭代:0encode_as_base64:假
这是怎么回事?
- 一个
json_user_provider
定义服务; - 一个
json
用户提供程序链接到我们的json_user_provider
服务; - 的
json
用户提供程序用于secured_area
防火墙; - 的
用户
密码编码器设置使用简单md5
散列。
此用户提供程序与身份验证机制是分离的,因此您可以使用它们中的任何一个:表单、API密钥、HTTP基础,等等。
使用自定义验证器
如果希望使用表单让用户输入凭据,可以使用内置的登录
身份验证系统:
1 2 3 4 5 6 7 8
安全:防火墙:secured_area:模式:^ /管理供应商:json登录:check_path:security_checklogin_path:登录
提示
有很多配置方法登录
,还有这个安全配置参考部分文档解释了它们。欧宝官网下载app
现在,假设我们希望用户只能在下午2点到4点之间(UTC时区)访问我们的网站。你会怎么做?显然,这种需求没有内置的配置设置。因此,我们需要自定义用户身份验证的方式。
有趣的部分来了。我们不创建自定义令牌、工厂、侦听器和提供程序,而是使用newob娱乐下载
改为接口(为了简单起见,我们在这里扩展了用户提供程序):
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
使用ob娱乐下载\组件\安全\核心\身份验证\SimpleFormAuthenticatorInterface;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\UsernamePasswordToken;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\核心\异常\UsernameNotFoundException;使用ob娱乐下载\组件\安全\核心\编码器\EncoderFactoryInterface;使用ob娱乐下载\组件\HttpFoundation\请求;类TimeAuthenticator扩展JsonUserProvider实现了SimpleFormAuthenticatorInterface{私人$encoderFactory;公共函数__construct(EncoderFactoryInterface$encoderFactory){$这->encoderFactory =$encoderFactory;}公共函数createToken(请求$请求,$用户名,$密码,$providerKey){返回新UsernamePasswordToken ($用户名,$密码,$providerKey);}公共函数authenticateToken(TokenInterface$令牌, UserProviderInterface$userProvider,$providerKey){试一试{$用户=$userProvider->loadUserByUsername ($令牌->getUsername ());}抓(UsernameNotFoundException$e) {扔新AuthenticationException (“无效的用户名或密码”);}$passwordValid=$这->encoderFactory->getEncoder ($用户)->isPasswordValid ($用户->getPassword (),$令牌->getCredentials (),$用户->getSalt ());如果($passwordValid) {$currentHour=日期(‘G’);如果($currentHour<14||$currentHour>16) {扔新AuthenticationException (“你只能在2点到4点之间登录!”,One hundred.);}返回新UsernamePasswordToken ($用户,“酒吧”,$providerKey,$用户->将getRoles ());}扔新AuthenticationException (“无效的用户名或密码”);}公共函数supportsToken(TokenInterface$令牌,$providerKey){返回$令牌运算符UsernamePasswordToken & &$令牌->getProviderKey () = = =$providerKey;}}
有很多事情正在发生:
createToken ()
创建一个Token,用于认证用户;authenticateToken ()
检查令牌
是否允许通过首先获取用户
通过用户提供程序,然后通过检查密码和当前时间(a令牌
使用角色进行身份验证);supportsToken ()
是一种允许多个身份验证机制用于同一防火墙的方法(这样,例如,您可以首先尝试通过证书或API密钥验证用户,然后退回到表单登录);需要一个编码器来检查用户密码的有效性;这是一个默认提供的服务:
1
$passwordValid=$这->encoderFactory->getEncoder ($用户)->isPasswordValid ($用户->getPassword (),$令牌->getCredentials (),$用户->getSalt ());
现在,我们如何将这个类连接到我们的配置中?因为我们已经扩展了ob娱乐下载
、替换登录
通过简单的形式
,并设置身份验证
选项。time_authenticator
服务:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
服务:time_authenticator:类:TimeAuthenticator参数:(@security.encoder_factory)安全:提供者:json:id:time_authenticator防火墙:secured_area:模式:^ /管理供应商:身份验证简单的形式:供应商:json身份验证:time_authenticatorcheck_path:security_checklogin_path:登录
如您所见,不需要创建侦听器,也不需要创建配置工厂。
自定义认证失败和成功
在验证机制之后,你有机会通过添加一些方法到你的authenticator类来调整默认行为:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\Http\身份验证\AuthenticationFailureHandlerInterface;使用ob娱乐下载\组件\安全\Http\身份验证\AuthenticationSuccessHandlerInterface;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\HttpFoundation\响应;类CustomTimeAuthenticator扩展TimeAuthenticator实现了AuthenticationFailureHandlerInterface,AuthenticationSuccessHandlerInterface{公共函数onAuthenticationFailure(请求$请求, AuthenticationException$异常){error_log (“你出局了!”);}公共函数onAuthenticationSuccess(请求$请求, TokenInterface$令牌){error_log (sprintf (“是的,你在“%s”!”,$令牌->getUsername ()));}}
这里,我们用error_log ()
函数记录一些信息。但是您也可以通过返回响应
实例:
1 2 3 4 5 6
公共函数onAuthenticationFailure(请求$请求, AuthenticationException$异常){如果($异常->getCode ()) {返回新响应(“现在不是登录的时候,待会儿再来吧。”);}}
使用API密钥对用户进行认证
现在,通过API密钥对用户进行身份验证是很常见的(例如,在开发web服务时)。API密钥为每个请求提供,并作为查询字符串参数或通过HTTP报头传递。
让我们对API键使用相同的JSON文件,但值现在是用户API键。基于请求信息对用户进行身份验证应该通过身份验证前机制完成。新ob娱乐下载
类可以很容易地实现这样的方案:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
使用ob娱乐下载\组件\安全\核心\身份验证\SimplePreAuthenticatorInterface;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\PreAuthenticatedToken;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\安全\核心\用户\用户;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\核心\异常\UsernameNotFoundException;使用ob娱乐下载\组件\安全\核心\异常\BadCredentialsException;类TimeAuthenticator扩展JsonUserProvider实现了SimplePreAuthenticatorInterface{受保护的$apikey;公共函数__construct(){父::__construct ();$这->Apikeys = array_flip($这->用户);}公共函数createToken(请求$请求,$providerKey){如果(!$请求->查询->有(“apikey”)) {扔新BadCredentialsException (“没有找到API键”);}返回新PreAuthenticatedToken (“不久。”,$请求->查询->get (“apikey”),$providerKey);}公共函数authenticateToken(TokenInterface$令牌, UserProviderInterface$userProvider,$providerKey){$currentHour=日期(‘G’);如果($currentHour<14||$currentHour>16) {扔新AuthenticationException (“你只能在2点到4点之间登录!”,One hundred.);}$apikey=$令牌->getCredentials ();如果(!收取($这->apikey [$apikey))) {扔新AuthenticationException (sprintf (“API密钥“%s”不存在。”,$apikey));}$用户=新用户($这->apikey [$apikey),$apikey,数组(“ROLE_USER”));返回新PreAuthenticatedToken ($用户,$令牌->getCredentials (),$providerKey,$用户->将getRoles ());}公共函数supportsToken(TokenInterface$令牌,$providerKey){返回$令牌运算符PreAuthenticatedToken & &$令牌->getProviderKey () = = =$providerKey;}}
可以看到,这个类看起来与基于表单的类几乎相同,只是我们使用的是ob娱乐下载
令牌类。
如果要访问该认证器保护的资源,需要添加apikey
参数设置为查询字符串,如inhttp://example.com/admin/foo?apikey=37b51d194a7513e45b56f6524f2d51f2
.
配置也很简单(替换简单的形式
与simple-preauth
):
1 2 3 4 5 6 7
安全:防火墙:secured_area:模式:^ /管理simple-preauth:供应商:json身份验证:time_authenticator
在防火墙中使用多个身份验证器
如果应用程序能够返回资源的HTML和JSON/XML表示,那么同时支持基于api密钥的身份验证机制(用于编程访问)和常规身份验证登录表单(用于浏览器)可能是个好主意。
这样做很简单:
12 3 4 5 6 7 8 9 10 11 12
安全:防火墙:secured_area:模式:^ /管理simple-preauth:供应商:json身份验证:pre_auth_time_authenticator简单的形式:供应商:json身份验证:form_time_authenticatorcheck_path:security_checklogin_path:登录
结论
我希望这种自定义Symfony安全特性的新方法将有助于降低新开发人员的入门门槛。ob娱乐下载这个新功能仍处于实验阶段,根据您的反馈,在2.4发布之前可能会有所改变。所以,试着使用它,告诉我们你的想法。
评论
评论截止。
为了确保评论保持相关性,旧帖子将被关闭。
Fabien Potencier is a certified Symfony engineer.
Get certified! Online exams available in all countries.
Register Now