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

编辑该页面

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

这个页面的更新版本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\实体;使用学说\ORM\映射作为ORM;使用ob娱乐下载\组件\安全\核心\用户\用户界面;/ * * *@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}

谨慎

在上面的示例中,表名用户。这是一个SQL关键字和保留必须用引号引用避免错误的教义。你也可以改变表名(例如app_user)来解决这个问题。

提示

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

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

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

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

步骤1)创建身份验证类

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

创建一个自定义的身份验证系统,就创建一个类,使其实现AuthenticatorInterface。或者,扩展更简单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
/ / src / AppBundle /安全/ TokenAuthenticator.php名称空间AppBundle\安全;使用ob娱乐下载\组件\HttpFoundation\JsonResponse;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\HttpFoundation\响应;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\核心\用户\用户界面;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\警卫\AbstractGuardAuthenticator;TokenAuthenticator扩展AbstractGuardAuthenticator{/ * * *呼吁每个请求决定如果这应该*用于身份验证请求。返回“false”将导致这个身份*被忽略。* /公共函数支持(请求美元请求){返回美元请求- >- >有(“X-AUTH-TOKEN”);}/ * * *呼吁每一个要求。返回任何凭证你想*被传递给getUser()美元凭证。* /公共函数getCredentials(请求美元请求){返回美元请求- >- >get (“X-AUTH-TOKEN”);}公共函数getUser(美元凭证,UserProviderInterface美元userProvider){如果(= = =美元凭证){/ /令牌头是空的,与HTTP认证失败状态/ /代码401“未经授权的”返回;}/ /如果用户返回,checkCredentials ()返回美元userProvider- >loadUserByUsername (美元凭证);}公共函数checkCredentials(美元凭证,用户界面美元用户){/ /检查凭证——例如确保密码是有效的/ /不需要凭证检查/ /返回true导致身份验证成功返回真正的;}公共函数onAuthenticationSuccess(请求美元请求,TokenInterface美元令牌,美元providerKey){/ /成功,让请求继续比赛返回;}公共函数onAuthenticationFailure(请求美元请求,AuthenticationException美元异常){美元数据= (/ /你可以定制或混淆消息“消息”= > strtr (美元异常- >getMessageKey (),美元异常- >getMessageData ())/ /或翻译这个消息/ / $ this - >翻译- >反式($例外- > getMessageKey(), $例外- > getMessageData ())];返回JsonResponse (美元数据、响应::HTTP_UNAUTHORIZED);}/ * * *时调用身份验证是必要的,但它不是发送* /公共函数开始(请求美元请求,AuthenticationException美元authException= null){美元数据= (/ /你会翻译这个消息“消息”= >身份验证所需的];返回JsonResponse (美元数据、响应::HTTP_UNAUTHORIZED);}公共函数supportsRememberMe(){返回;}}

3.4

AuthenticatorInterface是在Symfony 3.4中引入的。ob娱乐下载在以前的Symfony版ob娱乐下载本,实现所需的身份验证器GuardAuthenticatorInterface

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

步骤2)配置身份验证

要完成这一点,确保你的身份被注册为一个服务。如果你使用默认的服务。yml配置,自动发生。

最后,配置您的防火墙关键在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安全:#……防火墙:#……主要:匿名:~注销:~警卫:身份验证器:- - - - - -AppBundle \安全\ TokenAuthenticator#如果你想禁用用户存储在会话中无状态:真正的#或许其他的东西,像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 /#主页控制器执行:页面加载正常

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

警卫身份验证方法

每个身份需要以下方法:

支持请求(请求)

这是呼吁每一个请求和你的工作是决定是否应该使用身份验证请求(返回真正的如果它应该跳过(返回)或)。

3.4

支持()方法是在Symfony 3.4中引入的。ob娱乐下载在以前的Symfony版ob娱乐下载本,可以跳过身份返回getCredentials ()方法。

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

下图显示了如何Symfony调用后卫身份验证方法:ob娱乐下载

自定义错误信息

onAuthenticationFailure ()被调用时,通过了吗AuthenticationException描述如何验证未通过$例外- > getMessageKey ()(和$例外- > 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键:这只是一个愚蠢的短语“}

建立一个登录表单

如果您正在构建一个登录表单,使用AbstractFormLoginAuthenticator作为你的基类,它实现了一些方法给你。然后,填写的其他方法一样TokenAuthenticator。外,你还负责创建一个路线,控制器和模板为您的登录表单。

添加CSRF保护

如果您正在使用一个警卫身份构建一个登录表单和想要添加CSRF保护,没问题!

首先,_csrf_token添加到您的登录模板

然后,type-hintCsrfTokenManagerInterface在你的__construct ()方法(或手动配置security.csrf.token_manager服务传递)和添加以下逻辑:

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
/ / src / AppBundle /安全/ ExampleFormAuthenticator.php/ /……使用ob娱乐下载\组件\安全\核心\异常\InvalidCsrfTokenException;使用ob娱乐下载\组件\安全\Csrf\CsrfToken;使用ob娱乐下载\组件\安全\Csrf\CsrfTokenManagerInterface;使用ob娱乐下载\组件\安全\警卫\身份验证\AbstractFormLoginAuthenticator;ExampleFormAuthenticator扩展AbstractFormLoginAuthenticator{私人美元csrfTokenManager;公共函数__construct(CsrfTokenManagerInterface美元csrfTokenManager){美元- >csrfTokenManager =美元csrfTokenManager;}公共函数getCredentials(请求美元请求){美元csrfToken=美元请求- >请求- >get (“_csrf_token”);如果(= = =美元- >csrfTokenManager- >isTokenValid (CsrfToken (“验证”,美元csrfToken))){InvalidCsrfTokenException (“无效的CSRF令牌。”);}/ /……你所有的正常逻辑}/ /……}

避免对浏览器对每个请求进行身份验证

如果你创建一个后卫登录系统使用的浏览器,你正在经历的问题与你的会话或CSRF令牌,你的身份的原因可能是不良行为。当一个后卫身份验证是使用一个浏览器,你应该认证用户每一个请求。换句话说,你需要确保支持()方法只有返回真正的当你真正需要对用户进行身份验证。为什么?因为,当支持()返回true(身份验证是最终成功),出于安全目的,用户的会话是“迁移”到一个新的会话id。

这是一个极端例子,除非你有会话或CSRF令牌的问题,你可以忽略这一点。这是好的和坏的行为的一个例子:

1 2 3 4 5 6 7 8 9 10
公共函数支持(请求美元请求){/ /良好的行为:只有进行身份验证(即返回true)在一个特定的路线返回“login_route”= = =美元请求- >属性- >get (“_route”)& &美元请求- >isMethod (“职位”);/ /例如登录系统进行身份验证的用户的IP地址/ /不良行为:那么,你总是决定* *还真这样/ /你可以在每次请求用户的IP地址返回真正的;}

这个问题发生在你的浏览器试图验证用户身份每一个请求——就像在前面的例子基于IP地址。有两种可能的修复:

  1. 如果你做需要存储在会话中,身份验证设置无状态:真在你的防火墙。
  2. 更新你的身份,以避免认证如果用户已经通过身份验证:
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日
/ / src /安全/ MyIpAuthenticator。php / /……+使用Symob娱乐下载fony核心组件\ \安全\ \安全;类MyIpAuthenticator {美元+私人安全;+公共职能__construct(安全美元安全)+ {+ $ this - >安全= $安全;+}公共函数支持(请求请求美元){+ / /如果已经有一个身份验证的用户(可能由于会话)+ / /然后返回false,跳过认证:没有必要。+如果($ this - >安全- > getUser ()) {+返回false;+}+ / /用户没有登录,身份应该继续+返回true;}}

如果你使用自动装配,安全服务将自动传递给你的身份。

常见问题

我可以有多个身份验证器吗?
是的!但是当你做什么,你需要选择一个身份验证是你“entry_point”。这意味着你需要选择哪一个身份验证的start ()方法时应该调用一个匿名用户试图访问受保护的资源。更多细节,请参阅如何使用多个护卫的身份验证器吗
我可以使用这个与form_login吗?
是的!form_login一个验证一个用户,所以你可以使用它然后添加一个或多个身份验证器。使用一个后卫身份不与其他方法来验证相撞。
我可以使用这个与FOSUserBundle吗?
是的!实际上,FOSUserBundle不处理安全:它只是给你一个用户对象和一些路线和控制器帮助登录、注册、忘记密码,等。使用FOSUserBundle时,你通常使用form_login实际用户进行身份验证。你可以继续这样做(见以前的问题)或使用用户对象从FOSUserBundle和创建自己的身份(s)(就像在本文中)。
这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。