如何创建一个自定义的身份验证系统,保安吗

编辑该页面

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

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

如何创建一个自定义的身份验证系统,保安吗

是否需要建立一个传统的登录表单,一个API令牌认证系统或需要与一些专有的单点登录系统集成,警卫组件可以很容易…和乐趣!

在这个例子中,您将构建一个API令牌认证系统和学习如何使用。

创建用户和用户提供者

无论你如何进行身份验证,您需要创建一个用户类实现用户界面和配置用户提供者。在这个例子中,通过教义用户存储在数据库中,每个用户都有一个apiKey他们使用通过API来访问自己的帐户:

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
/ / src / AppBundle /实体/ User.php名称空间AppBundle\实体;使用ob娱乐下载\组件\安全\核心\用户\用户界面;使用学说\ORM\映射作为ORM;/ * * *@ORM* \实体@ORM\表(name = "用户")* /用户实现了用户界面{/ * * *@ORM\ Id *@ORM\ GeneratedValue(策略=“汽车”)*@ORM\列(类型=“整数”)* /私人美元id;/ * * *@ORM\列(type =“字符串”,独特的= true) * /私人美元用户名;/ * * *@ORM\列(type =“字符串”,独特的= true) * /私人美元apiKey;公共函数getUsername(){返回美元- >用户名;}公共函数将getRoles(){返回(“ROLE_USER”];}公共函数getPassword(){}公共函数getSalt(){}公共函数eraseCredentials(){}/ /更多的getter / setter}

提示

这个用户没有密码,但是你可以添加一个密码财产,如果你还想让这个用户登录和密码(例如通过一个登录表单)。

你的用户类不需要存储在教义:做任何你需要的东西。接下来,确保你配置一个用户的“用户提供者”:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10
# app / config / security.yml安全:#……提供者:your_db_provider:实体:类:AppBundle:用户#……

就是这样!关于这一步需要更多的信息,请参阅:

步骤1)创建身份验证类

假设您有一个API,你的客户将会发送一个X-AUTH-TOKEN头在每个请求API令牌。你的工作是阅读这并找到相关的用户(如果有的话)。

创建一个自定义的身份验证系统,就创建一个类,使其实现GuardAuthenticatorInterface。或者,扩展更简单AbstractGuardAuthenticator。这需要你来实现六个方法:

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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
/ / src / AppBundle /安全/ TokenAuthenticator.php名称空间AppBundle\安全;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\HttpFoundation\JsonResponse;使用ob娱乐下载\组件\安全\核心\用户\用户界面;使用ob娱乐下载\组件\安全\警卫\AbstractGuardAuthenticator;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用学说\ORM\EntityManager;TokenAuthenticator扩展AbstractGuardAuthenticator{私人美元新兴市场;公共函数__construct(EntityManager美元新兴市场){美元- >em =美元新兴市场;}/ * * *呼吁每一个要求。返回任何你想要的证书,*或null停止认证。* /公共函数getCredentials(请求美元请求){如果(!美元令牌=美元请求- >- >get (“X-AUTH-TOKEN”)){/ /没有令牌?返回null,没有其他方法将被调用返回;}/ /这里你还将被传递给getUser()美元凭证返回数组(“令牌”= >美元令牌,);}公共函数getUser(美元凭证,UserProviderInterface美元userProvider){美元apiKey=美元凭证(“令牌”];/ /如果是null,身份验证就会失败/ /如果用户对象,checkCredentials ()返回美元- >新兴市场- >getRepository (“AppBundle:用户”)- >findOneBy (数组(“apiKey”= >美元apiKey));}公共函数checkCredentials(美元凭证,用户界面美元用户){/ /检查凭证——例如确保密码是有效的/ /不需要凭证检查/ /返回true导致身份验证成功返回真正的;}公共函数onAuthenticationSuccess(请求美元请求,TokenInterface美元令牌,美元providerKey){/ /成功,让请求继续比赛返回;}公共函数onAuthenticationFailure(请求美元请求,AuthenticationException美元异常){美元数据=数组(“消息”= > strtr (美元异常- >getMessageKey (),美元异常- >getMessageData ())/ /或翻译这个消息/ / $ this - >翻译- >反式($例外- > getMessageKey(), $例外- > getMessageData ()));返回JsonResponse (美元数据,403年);}/ * * *时调用身份验证是必要的,但它不是发送* /公共函数开始(请求美元请求,AuthenticationException美元authException= null){美元数据=数组(/ /你会翻译这个消息“消息”= >身份验证所需的);返回JsonResponse (美元数据,401年);}公共函数supportsRememberMe(){返回;}}

不错的工作!每个方法解释如下:警卫身份验证方法

步骤2)配置身份验证

要完成这一点,注册类服务:

  • YAML
  • XML
  • PHP
1 2 3 4 5
# app / config / services.yml服务:app.token_authenticator:类:AppBundle \安全\ TokenAuthenticator参数:(“@doctrine.orm.entity_manager”)

最后,配置您的防火墙关键在security.yml使用这个身份:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# app / config / security.yml安全:#……防火墙:#……主要:匿名:~注销:~警卫:身份验证器:- - - - - -app.token_authenticator#如果你想禁用用户存储在会话中无状态:真正的#或许其他的东西,像form_login, remember_me等等#……

你做到了!您现在拥有了一个有效的API令牌认证系统。如果你的首页需要ROLE_USER,然后你可以测试它在不同条件下:

1 2 3 4 5 6 7 8 9 10 11
#测试没有令牌curl http://localhost: 8000 /#{“消息”:“身份验证需要“}#测试坏牌curl - h“X-AUTH-TOKEN:假”http://localhost: 8000 /#{“消息”:“用户名无法找到。”}#测试工作牌curl - h“X-AUTH-TOKEN:真正的”http://localhost: 8000 /#主页控制器执行:页面加载正常

现在,了解更多关于什么每个方法。

警卫身份验证方法

每个身份需要以下方法:

美元getCredentials(请求请求)
这将是呼吁<新兴市场>每一个请求和你的工作是阅读令牌(或无论你“身份验证”信息)从请求并返回。如果你返回身份验证过程的,其余是跳过。否则,getUser ()将调用和返回值是作为第一个参数传递。
getUser(美元凭证,UserProviderInterface userProvider美元)
如果getCredentials ()返回一个null值,然后调用此方法,它的返回值是通过这里美元的凭证论点。你的工作是实现返回一个对象用户界面。如果你这样做,checkCredentials ()将被调用。如果你返回(或者抛出一个AuthenticationException身份验证失败。
checkCredentials(凭证美元,用户界面用户)
如果getUser ()返回一个用户对象,调用此方法。你的工作是验证凭证是正确的。对于一个登录表单,这就是你会检查用户的密码是否正确。通过身份验证、回报真正的。如果你返回<新兴市场>任何东西其他(或抛出AuthenticationException),身份验证就会失败。
onAuthenticationSuccess(请求请求美元,美元TokenInterface令牌,providerKey美元)
这就是所谓的成功的身份验证之后,你的工作是返回一个响应对象将被发送到客户端继续请求(例如,允许路线/控制器被称为像正常)。因为这是一个API,每个请求进行身份验证本身,你想回来
onAuthenticationFailure(请求请求美元,美元AuthenticationException除外)
这就是所谓的如果认证失败。你的工作是回报响应对象,应发送给客户机。的美元的例外会告诉你<新兴市场>什么在身份验证错误。
开始(请求$请求,AuthenticationException authException美元= null)
这叫做如果客户机访问一个URI /资源,需要认证,但是没有发送验证信息(即你返回getCredentials ())。你的工作是返回一个响应对象,帮助用户进行身份验证(例如,一个401响应说,“令牌丢失!”)。
supportsRememberMe
如果你想支持“记住我”功能,从这个方法返回true。你仍然需要活跃remember_me在你的防火墙工作。由于这是一个无状态的API,您不想在这个例子中支持“记住我”功能。

自定义错误信息

onAuthenticationFailure ()被调用时,通过了吗AuthenticationException描述<新兴市场>如何验证未通过$ e - > getMessageKey ()(和$ e - > getMessageData ())方法。消息将被不同的基础上<新兴市场>在哪里身份验证失败(即。getUser ()checkCredentials ())。

但是,您可以轻松地返回一个自定义消息通过投掷CustomUserMessageAuthenticationException。你可以把这个getCredentials (),getUser ()checkCredentials ()导致一个失败:

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 /安全/ TokenAuthenticator.php/ /……使用ob娱乐下载\组件\安全\核心\异常\CustomUserMessageAuthenticationException;TokenAuthenticator扩展AbstractGuardAuthenticator{/ /……公共函数getCredentials(请求美元请求){/ /……如果(美元令牌= =“ILuvAPIs”){CustomUserMessageAuthenticationException (ILuvAPIs不是一个真正的API密匙:\ ' s只是一个愚蠢的说法“);}/ /……}/ /……}

在这种情况下,由于“ILuvAPIs”是一个荒谬的API密匙,你可能包括一个复活节彩蛋返回一个自定义消息如果有人尝试:

1 2
curl - h“X-AUTH-TOKEN: ILuvAPIs”http://localhost: 8000 /#{“消息”:“ILuvAPIs不是一个真正的API键:这只是一个愚蠢的短语“}

常见问题

我可以有多个身份验证器吗?

是的!但是当你做什么,你需要选择<新兴市场>一个身份验证是你“entry_point”。这意味着你需要选择<新兴市场>哪一个身份验证的start ()方法时应该调用一个匿名用户试图访问受保护的资源。例如,假设您有一个app.form_login_authenticator处理一个传统形式登录。当一个匿名用户访问一个受保护的页面,你想使用start ()从表单身份验证方法,将他们重定向到登录页面(而不是返回一个JSON响应):

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# app / config / security.yml安全:#……防火墙:#……主要:匿名:~注销:~警卫:身份验证器:- - - - - -app.token_authenticator#如果你想禁用用户存储在会话中无状态:真正的#或许其他的东西,像form_login, remember_me等等#……
我可以用这个吗form_login吗?
是的!form_login是<新兴市场>一个验证一个用户,所以你可以使用它<新兴市场>和然后添加一个或多个身份验证器。使用一个后卫身份不与其他方法来验证相撞。
我可以使用这个与FOSUserBundle吗?
是的!实际上,FOSUserBundle不处理安全:它只是给你一个用户对象和一些路线和控制器帮助登录、注册、忘记密码,等。使用FOSUserBundle时,你通常使用form_login实际用户进行身份验证。你可以继续这样做(见以前的问题)或使用用户对象从FOSUserBundle和创建自己的身份(s)(就像在本文中)。
这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。