自定义的身份验证系统保护(API象征性的例子)
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 5.0,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。
自定义的身份验证系统保护(API象征性的例子)
卫兵认证可用于:
- 建立一个登录表单
- 创建一个API令牌认证系统(见下文)
- 社会身份验证(或使用HWIOAuthBundle一个健壮的non-Guard解决方案)
- 与一些专有的单点登录系统集成
和许多更多。在本例中,我们将构建一个API令牌认证系统,我们可以详细了解更多保护。
步骤1)准备您的用户类
假设您想要构建一个API,你的客户将发送一个X-AUTH-TOKEN
头在每个请求API令牌。你的工作是阅读这并找到相关的用户(如果有的话)。
首先,确保你跟随主安全指南创建您的用户
类。然后,为简单起见,添加一个apiToken
财产直接向您用户
类(:实体
命令是一个很好的方法):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/ / src /实体/用户。php / /……类用户实现用户界面{/ /……+ / * *+ * @ORM \列(type =“字符串”,独特的= true, nullable = true)+ * /+私人apiToken美元;/ / getter和setter方法}
不要忘记来生成和执行迁移:
1 2
美元php bin /控制台:迁移美元php bin /控制台学说:迁移:迁移
步骤2)创建Authenticator类
创建一个自定义的身份验证系统,创建一个类,使其实现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 92 93 94 95 96 97 98 99 100 101 102
/ / src /安全/ TokenAuthenticator.php名称空间应用程序\安全;使用应用程序\实体\用户;使用学说\ORM\EntityManagerInterface;使用ob娱乐下载\组件\HttpFoundation\JsonResponse;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\HttpFoundation\响应;使用ob娱乐下载\组件\安全\核心\身份验证\令牌\TokenInterface;使用ob娱乐下载\组件\安全\核心\异常\AuthenticationException;使用ob娱乐下载\组件\安全\核心\用户\用户界面;使用ob娱乐下载\组件\安全\核心\用户\UserProviderInterface;使用ob娱乐下载\组件\安全\警卫\AbstractGuardAuthenticator;类TokenAuthenticator扩展AbstractGuardAuthenticator{私人美元新兴市场;公共函数__construct(EntityManagerInterface美元新兴市场){美元这- >em =美元新兴市场;}/ * * *呼吁每个请求决定如果这应该*用于身份验证请求。返回“false”将导致这个身份*被忽略。* /公共函数支持(请求美元请求){返回美元请求- >头- >有(“X-AUTH-TOKEN”);}/ * * *呼吁每一个要求。返回任何凭证你想*被传递给getUser()美元凭证。* /公共函数getCredentials(请求美元请求){返回美元请求- >头- >get (“X-AUTH-TOKEN”);}公共函数getUser(美元凭证,UserProviderInterface美元userProvider){如果(零= = =美元凭证){/ /令牌头是空的,与HTTP认证失败状态/ /代码401“未经授权的”返回零;}/ /如果用户返回,checkCredentials ()返回美元这- >新兴市场- >getRepository(用户::类)- >findOneBy ([“apiToken”= >美元凭证]);}公共函数checkCredentials(美元凭证,用户界面美元用户){/ /检查凭证——例如确保密码是有效的。/ /在一个API令牌的情况下,不需要凭证检查。/ /返回“true”导致身份验证成功返回真正的;}公共函数onAuthenticationSuccess(请求美元请求,TokenInterface美元令牌,美元providerKey){/ /成功,让请求继续比赛返回零;}公共函数onAuthenticationFailure(请求美元请求,AuthenticationException美元异常){美元数据= (/ /你可以定制或混淆消息“消息”= > strtr (美元异常- >getMessageKey (),美元异常- >getMessageData ())/ /或翻译这个消息/ / $ this - >翻译- >反式($例外- > getMessageKey(), $例外- > getMessageData ())];返回新JsonResponse (美元数据、响应::HTTP_UNAUTHORIZED);}/ * * *时调用身份验证是必要的,但它不是发送* /公共函数开始(请求美元请求,AuthenticationException美元authException= null){美元数据= (/ /你会翻译这个消息“消息”= >身份验证所需的];返回新JsonResponse (美元数据、响应::HTTP_UNAUTHORIZED);}公共函数supportsRememberMe(){返回假;}}
不错的工作!每个方法解释如下:警卫身份验证方法。
步骤3)配置身份验证
要完成这一点,确保你的身份被注册为一个服务。如果你使用默认的服务。yaml的配置,自动发生。
最后,配置您的防火墙
关键在security.yaml
使用这个身份:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#配置/包/ security.yaml安全:#……防火墙:#……主要:匿名:懒惰的注销:~警卫:身份验证器:- - - - - -App \安全\ TokenAuthenticator#如果你想禁用用户存储在会话中无状态:真正的#……
你做到了!您现在拥有了一个有效的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 ()
。你的工作是实现返回一个对象用户界面
。如果你这样做,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 /安全/ 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键:这只是一个愚蠢的短语“}
手动验证用户
有时你可能需要手动验证用户,比如当用户完成注册。要做到这一点,用你的身份和一个服务调用GuardAuthenticatorHandler
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日
/ / src /控制器/ RegistrationController.php/ /……使用应用程序\安全\LoginFormAuthenticator;使用ob娱乐下载\组件\HttpFoundation\请求;使用ob娱乐下载\组件\安全\警卫\GuardAuthenticatorHandler;类RegistrationController扩展AbstractController{公共函数注册(LoginFormAuthenticator美元身份验证,GuardAuthenticatorHandler美元guardHandler,请求美元请求){/ /……/ /验证用户并保存后到数据库/ /验证用户身份验证和使用onAuthenticationSuccess返回美元guardHandler- >authenticateUserAndHandleSuccess (美元用户,/ /您刚才创建的User对象美元请求,美元身份验证,/ / onAuthenticationSuccess您想要使用的身份验证“主要”/ /你的名字在security.yaml防火墙);}}
避免对浏览器对每个请求进行身份验证
如果你创建一个后卫登录系统使用的浏览器,你正在经历的问题与你的会话或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 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)(就像在本文中)。