如何创建一个自定义身份验证提供者

编辑该页面

警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 3.1,不再维护。

这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。

如何创建一个自定义身份验证提供者

提示

创建一个自定义的身份验证系统是很难的,这个条目将指导您完成这一过程。但根据你的需要,你可以以一个更简单的方式解决你的问题,或者通过一个社区包:欧宝体育平台怎么样

如果你读过这一章安全,你理解Symfony的区别使得安全的身份验证和授权之间实现。ob娱乐下载本章讨论了身份验证过程中涉及的核心类,以及如何实现一个定制的身份验证提供者。因为身份验证和授权是不同的概念,这个扩展将user-provider不可知论者,并将与您的应用程序的功能用户提供者,他们可能位于内存数据库,或其他任何你选择存储它们。

满足WSSE

第二章演示如何创建一个自定义身份验证提供者WSSE身份验证。WSSE提供了一些保障福利的安全协议:

  1. 用户名/密码加密
  2. 安全防范重放攻击
  3. 不需要web服务器配置

WSSE为web服务的获得是非常有用的,他们可能是SOAP或REST。

有大量的文档欧宝官网下载appWSSE,但是本文将重点不是在安全协议,而是一个自定义协议的方式可以添加到您的Symfony应用程序。ob娱乐下载WSSE的基础是请求头检查加密证书,使用时间戳和验证现时标志请求的用户使用一个密码,验证消化。

请注意

关键WSSE还支持应用程序进行验证时,web服务是有用的,但已经超出了本章的范围。

令牌

在Symfony安全上下文令牌的作用很重要。ob娱乐下载一个令牌代表了用户身份验证数据出现在请求。一旦身份验证请求,令牌保留用户的数据,整个安全上下文,并将这些数据。首先,您将创建你的令牌类。这将允许的所有相关信息传递到您的身份验证提供者。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日24
/ / src / AppBundle /安全/认证/令牌/ WsseUserToken.php名称空间AppBundle\安全\身份验证\令牌;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\AbstractToken;WsseUserToken扩展AbstractToken{公共美元创建;公共美元消化;公共美元现时标志;公共函数__construct(数组美元角色=数组()){::__construct (美元角色);/ /如果用户角色,考虑进行身份验证美元- >setAuthenticated (count (美元角色)>0);}公共函数getCredentials(){返回;}}

请注意

WsseUserToken类扩展了安全组件的AbstractToken类,它提供了基本的标记功能。实现TokenInterface在任何类作为一个令牌。

侦听器

接下来,您需要一个监听器监听防火墙。侦听器负责防火墙部署请求,调用身份验证提供者。一个监听器必须的一个实例ListenerInterface。一个安全侦听器应该处理GetResponseEvent事件,并设置令牌存储如果成功的身份验证令牌。

1 2 3 4 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 53 54 55 56 57 58 59 60 61
/ / src / AppBundle /安全/防火墙/ WsseListener.php名称空间AppBundle\安全\防火墙;使用ob娱乐下载\组件\HttpFoundation\响应;使用ob娱乐下载\组件\HttpKernel\事件\GetResponseEvent;使用ob娱乐下载\组件\安全\核心\身份验证\AuthenticationManagerInterface;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\存储\TokenStorageInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\Http\防火墙\ListenerInterface;使用AppBundle\安全\身份验证\令牌\WsseUserToken;WsseListener实现了ListenerInterface{受保护的美元tokenStorage;受保护的美元authenticationManager;公共函数__construct(TokenStorageInterface美元tokenStorage,AuthenticationManagerInterface美元authenticationManager){美元- >tokenStorage =美元tokenStorage;美元- >authenticationManager =美元authenticationManager;}公共函数处理(GetResponseEvent美元事件){美元请求=美元事件- >getRequest ();美元wsseRegex=' / UsernameToken用户名= " ([^]+)”,PasswordDigest = " ([^] +)”,现时标志="([a-zA-Z0-9+\/]+={0,2})", Created="([^"]+)"/'< /span>;如果(!美元请求- >- >有(“x-wsse”)| |1! = = preg_match (美元wsseRegex,美元请求- >- >get (“x-wsse”),美元匹配)){返回;}美元令牌=WsseUserToken ();美元令牌- >setUser (美元匹配(1]);美元令牌- >消化=美元匹配(2];美元令牌- >现时标志=美元匹配(3];美元令牌- >创建了=美元匹配(4];试一试{美元authToken=美元- >authenticationManager- >验证(美元令牌);美元- >tokenStorage- >setToken (美元authToken);返回;}(AuthenticationException美元失败的){/ /……你可能会记录一些东西/ /否认身份验证令牌。这将重定向到登录页面。/ /一定要清楚你的令牌,而不是其他身份验证的听众。/ / $牌= $ this - > tokenStorage - > getToken ();/ /如果($牌instanceof WsseUserToken & & $ this - > providerKey = = = $令牌- > getProviderKey ()) {/ / $ this - > tokenStorage - > setToken(空);/ /}/ /返回;}/ /默认拒绝授权美元响应=反应();美元响应- >setStatusCode(响应::HTTP_FORBIDDEN);美元事件- >setResponse (美元响应);}}

该侦听器检查请求的预期X-WSSE头,匹配预期的返回值WSSE信息,使用这些信息创建一个令牌,令牌传递身份验证管理器。如果不提供适当的信息,或身份验证管理器抛出AuthenticationException,将返回一个403响应。

请注意

上面一个类不习惯,AbstractAuthenticationListener类,是一种非常有用的基类为安全提供通常需要的功能扩展。这包括维护会话令牌,提供成功/失败处理程序,登录表单url,以及更多。因为WSSE不需要维护或登录的身份验证会话形式,它不会被用于此示例。

请注意

过早返回于侦听器相关只有如果你想链身份验证提供者(例如,允许匿名用户)。如果你想禁止访问匿名用户和有一个漂亮的403错误,你应该设定响应返回的状态码。

身份验证提供者

身份验证提供者的验证WsseUserToken。也就是说,供应商将验证创建头值是有效的在五分钟内,现时标志头的价值是独一无二的在五分钟内,PasswordDigest标题和值匹配用户的密码。

1 2 3 4 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
/ / src / AppBundle /安全/认证/供应商/ WsseProvider.php名称空间AppBundle\安全\身份验证\提供者;使用Psr\缓存\CacheItemPoolInterface;使用ob娱乐下载\组件\安全\核心\身份验证\提供者\AuthenticationProviderInterface;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\核心\异常\NonceExpiredException;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用AppBundle\安全\身份验证\令牌\WsseUserToken;WsseProvider实现了AuthenticationProviderInterface{私人美元userProvider;私人美元cachePool;公共函数__construct(UserProviderInterface美元userProvider,CacheItemPoolInterface美元cachePool){美元- >userProvider =美元userProvider;美元- >cachePool =美元cachePool;}公共函数进行身份验证(TokenInterface美元令牌){美元用户=美元- >userProvider- >loadUserByUsername (美元令牌- >getUsername ());如果(美元用户& &美元- >validateDigest (美元令牌- >消化,美元令牌- >现时标志,美元令牌- >创建,美元用户- >getPassword ())) {美元authenticatedToken=WsseUserToken (美元用户- >将getRoles ());美元authenticatedToken- >setUser (美元用户);返回美元authenticatedToken;}AuthenticationException (“WSSE身份验证失败了。”);}/ * * *这个函数是特定于Wsse身份验证和这个例子只是用来帮助* *特定逻辑的更多信息,参见https://github.com/symfony/symfony-docs/pull/3134 * # issuecomment - 27699129 * /ob娱乐下载受保护的函数validateDigest(美元消化,美元现时标志,美元创建,美元秘密){/ /检查创建时间不是在未来如果(strtotime (美元创建)>时间()){返回;}/ /时间戳5分钟后过期如果(时间()——strtotime (美元创建)>300年){返回;}/ /从池获取缓存项美元cacheItem=美元- >cachePool- >getItem (md5 (美元现时标志));/ /验证nonce *不*在缓存中/ /如果是,这可能是一个重放攻击如果(美元cacheItem- >isHit ()) {NonceExpiredException (“以前nonce检测”);}/ /存储在缓存项5分钟美元cacheItem- >集()- >expiresAfter (300年);美元- >cachePool- >保存(美元cacheItem);/ /验证的秘密美元预期= base64_encode (sha1 (base64_decode (美元现时标志)。美元创建美元秘密,真正的));返回hash_equals (美元预期,美元消化);}公共函数支持(TokenInterface美元令牌){返回美元令牌运算符WsseUserToken;}}

请注意

AuthenticationProviderInterface需要一个authenticate ()方法在用户令牌和一个支持()方法,它告诉身份验证管理器使用这个供应商是否为给定的令牌。在多个提供者的情况下,认证管理器将会移动到下一个提供者列表中。

请注意

hash_equals函数是在PHP 5.6中引入的,你是安全的使用它与任何PHP版本在Symfony应用程序。ob娱乐下载在PHP版本5.6之前,ob娱乐下载Symfony Polyfill(包括在Symfony)将为您定义的函数。ob娱乐下载

工厂

您已经创建了一个自定义令牌、自定义侦听器和自定义服务提供方程序。现在你需要把它们放在一起。你如何为每个防火墙提供一个独特的供应商吗?答案是通过使用一个工厂。工厂是你钩到安全组件,告诉您的供应商的名称和任何配置选项。首先,您必须创建一个类实现SecurityFactoryInterface

1 2 3 4 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
/ / src / AppBundle / DependencyInjection /安全/工厂/ WsseFactory.php名称空间AppBundle\DependencyInjection\安全\工厂;使用ob娱乐下载\组件\DependencyInjection\ContainerBuilder;使用ob娱乐下载\组件\DependencyInjection\参考;使用ob娱乐下载\组件\DependencyInjection\DefinitionDecorator;使用ob娱乐下载\组件\配置\定义\构建器\NodeDefinition;使用ob娱乐下载\\SecurityBundle\DependencyInjection\安全\工厂\SecurityFactoryInterface;WsseFactory实现了SecurityFactoryInterface{公共函数创建(ContainerBuilder美元容器,美元id,美元配置,美元userProvider,美元defaultEntryPoint){美元providerId=“security.authentication.provider.wsse”。美元id;美元容器- >setDefinition (美元providerId,DefinitionDecorator (“wsse.security.authentication.provider”))- >replaceArgument (0,引用(美元userProvider));美元listenerId=“security.authentication.listener.wsse”。美元id;美元侦听器=美元容器- >setDefinition (美元listenerId,DefinitionDecorator (“wsse.security.authentication.listener”));返回数组(美元providerId,美元listenerId,美元defaultEntryPoint);}公共函数getPosition(){返回“pre_auth”;}公共函数getKey(){返回“wsse”;}公共函数addConfiguration(NodeDefinition美元节点){}}

SecurityFactoryInterface需要以下的方法:

create ()
方法添加侦听器和身份验证提供者的DI容器适当的安全上下文。
getPosition ()
当提供者应该被称为收益。这可以之一pre_auth,形式,httpremember_me
getKey ()
方法定义了配置防火墙的关键用来引用提供者配置。
addConfiguration ()
方法用于定义下面的配置选项配置键入你的安全配置。设置配置选项在本章后面解释。

请注意

一个类不习惯在这个例子中,AbstractFactory是一个非常有用的基类,提供了安全的工厂通常需要的功能。它可能是有用的在定义不同类型的身份验证提供者。

现在,您已经创建了一个工厂类,wsse键可以用来作为防火墙的安全配置。

请注意

你也许会问“为什么你需要一个特殊的工厂类听众和提供者添加到依赖注入容器?”。这是一个非常好的问题。原因是你可以多次使用防火墙,确保您的应用程序的多个部分。正因为如此,每次使用防火墙,DI容器创建一个新的服务。工厂就是创建这些新服务。

配置

是时候看到你的身份验证提供者。你需要做几件事为了使这项工作。第一件事是将上面的服务添加到DI容器。你的工厂类以上使服务id引用不存在:wsse.security.authentication.providerwsse.security.authentication.listener。是时候来定义这些服务。

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13
# app / config / services.yml服务:wsse.security.authentication.provider:类:AppBundle \安全\验证\ \ WsseProvider提供者参数:- - - - - -#用户提供者- - - - - -“@cache.app”公众:wsse.security.authentication.listener:类:AppBundle \安全\ \ WsseListener防火墙参数:(“@security.token_storage”,“@security.authentication.manager”]公众:

现在你的服务定义,你告诉你的安全上下文工厂包类:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src / AppBundle / AppBundle.php名称空间AppBundle;使用AppBundle\DependencyInjection\安全\工厂\WsseFactory;使用ob娱乐下载\组件\HttpKernel\\;使用ob娱乐下载\组件\DependencyInjection\ContainerBuilder;AppBundle扩展{公共函数构建(ContainerBuilder美元容器){::构建(美元容器);美元扩展=美元容器- >getExtension (“安全”);美元扩展- >addSecurityListenerFactory (WsseFactory ());}}

你完成!现在,您可以定义WSSE保护你的应用程序的一部分。

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9
# app / config / security.yml安全:#……防火墙:wsse_secured:模式:^ / api /无状态:真正的wsse:真正的

恭喜你!你写你自己的自定义安全身份验证提供者!

一些额外的

如何让你的WSSE身份验证提供者更令人兴奋的呢?可能性是无限的。你为什么不先添加一些闪闪发光,发光吗?

配置

你可以添加自定义选项下wsse关键在你的安全配置。例如,允许在到期之前的时间创建头项,默认情况下,是5分钟。让这个可配置的,所以不同的防火墙可以有不同的超时长度。

你将首先需要编辑WsseFactory和定义的新选项addConfiguration ()方法。

1 2 3 4 5 6 7 8 9 10 11 12
WsseFactory实现了SecurityFactoryInterface{/ /……公共函数addConfiguration(NodeDefinition美元节点){美元节点- >孩子()- >scalarNode (“一生”)- >defaultValue (300年)- >结束();}}

现在,在create ()工厂的方法,美元配置参数将包含一个一生键,设置为5分钟(300秒)除非另有中设置配置。这个参数传递给你的身份验证提供者为了使用它了。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
WsseFactory实现了SecurityFactoryInterface{公共函数创建(ContainerBuilder美元容器,美元id,美元配置,美元userProvider,美元defaultEntryPoint){美元providerId=“security.authentication.provider.wsse”。美元id;美元容器- >setDefinition (美元providerId,DefinitionDecorator (“wsse.security.authentication.provider”))- >replaceArgument (0,引用(美元userProvider))- >replaceArgument (2,美元配置(“一生”]);/ /……}/ /……}

请注意

你还需要添加第三个参数wsse.security.authentication.provider服务配置,可以空白,但将在一生的工厂。的WsseProvider类将现在也需要接受第三个构造函数参数——一生——它应该使用而不是硬编码的300秒。这里没有显示这两个步骤。

的生命周期每个WSSE请求现在是可配置的,并且可以设置为任何可取的价值/防火墙。

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9
# app / config / security.yml安全:#……防火墙:wsse_secured:模式:^ / api /无状态:真正的wsse:{生命周期:30.}

剩下的是你!任何相关的配置项可以定义在工厂和消费或传递到其他类的容器。

这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。