I'm looking into implementing OpenID, but I drawing a blank as to how the database would look with new / existing users. How does * do it? I understand the concept that an external site does the authentication for me, but as far as storing user information on my end I need help with.
我正在研究如何实现OpenID,但对于数据库如何与新的/现有用户一起使用,我没有给出答案。*是怎么做到的?我理解外部站点为我进行身份验证的概念,但是对于在我这边存储用户信息,我需要帮助。
1 个解决方案
#1
12
Since this is one of the top search results when searching for OpenID Database Structures on Google, and the Plaxo link referenced in the previous answer is no longer around. I've copied and pasted the content of the Plaxo instructions below. I was able to get them by using the wayback machine page referenced here. Keep in mind that because of *'s 30000 character restrictions, I will have to crop certain sections, and Joseph Smarr included some images in his instructions, so you might want to look at the wayback machine page I referenced. -Jason
因为在谷歌上搜索OpenID数据库结构时,这是最重要的搜索结果之一,并且前面的答案中引用的Plaxo链接已经不复存在。我已经复制粘贴了下面Plaxo指令的内容。我可以使用这里引用的wayback机器页面来获得它们。请记住,由于*的3万个字符限制,我将不得不裁剪某些部分,而Joseph Smarr在他的指令中包含了一些图像,所以您可能想要查看我引用的wayback machine页面。杰森
A Recipe for OpenID-Enabling Your Site
Prepared by Joseph Smarr at Plaxo on July 18, 2007.
2007年7月18日,约瑟夫·斯玛在Plaxo编写。
This is a step-by-step tutorial guide for implementing OpenID consumer-side support with a web site that already has users with accounts. It will explain how to easily let new users sign up for an account on your site using their OpenID URL and how to let existing users attach their OpenID(s) so they can sign in using them.
这是一个循序渐进的教程指南,用于实现OpenID客户端支持,该网站已经拥有帐户用户。它将解释如何方便地让新用户使用他们的OpenID URL注册您的站点上的一个帐户,以及如何让现有用户附加他们的OpenID,以便他们可以使用它们登录。
I developed this guide by talking to fellow OpenID developers at the Internet Identity Workshop and elsewhere, and by implementing OpenID support for Plaxo using these instructions. I've also posted detailed screenshots of Plaxo's implementation for reference. I've intended for this guide to be clear and complete and to follow best-practices, but if you have any questions or feedback, please let me know at ob_male('joseph','plaxo.com'); or by posting a comment on Plaxo's blog.
我在Internet Identity研讨会和其他地方与OpenID开发人员进行了交谈,并使用这些说明实现了对Plaxo的OpenID支持。我还发布了Plaxo的实现的详细截图,以供参考。我希望本指南清晰完整,并遵循最佳实践,但如果您有任何问题或反馈,请在ob_male('joseph','plaxo.com')让我知道;或者在Plaxo的博客上发表评论。
This guide may look a bit long, but my hope is you can just follow it straight through without thinking much, and you'll be completely done by the time you reach the end! :)
这个指南可能看起来有点长,但我希望你可以直接按照它进行,而不需要想太多,你将完全完成,当你到达终点!:)
Overview
I'm assuming your web site currently has:
我假设你的网站目前有:
- A user database with rows for each user
- Each user has a unique internal user ID
- 每个用户都有一个惟一的内部用户ID。
- Users currently sign in using a username/e-mail and password
- 用户目前使用用户名/电子邮件和密码登录
- 一个用户数据库中,每个用户都有一个唯一的内部用户ID,用户当前使用用户名/电子邮件和密码进行签名
- A registration flow for signing up new users and getting collecting basic profile info
- 注册流程,用于注册新用户并获取基本的配置信息
- A signin page for authenticating users
- Internally you authenticate users based on username/e-mail and password, look up their unique user ID, and use it in the rest of your site
- 在内部,您根据用户名/电子邮件和密码对用户进行身份验证,查找他们的唯一用户ID,并在站点的其他部分使用它
- 用户身份验证的登录页面,您可以基于用户名/电子邮件和密码对用户进行身份验证,查找他们的唯一用户ID,并在站点的其他部分使用它
- A settings page for users to manage their account info.
- 用户管理帐户信息的设置页面。
If your site doesn't look like this, you should still be able to follow along, but some of the sections may not be relevant to you.
如果你的网站看起来不像这样,你仍然可以跟随,但是有些部分可能与你无关。
Snipped.. so check the wayback machine link up above for the rest.
剪掉. .所以,请查看上面的回程机链接。
Implementation details
- There are OpenID libraries already available in many popular programming languages that will do almost all of the heavy lifting for you. The team at JanRain wrote a bunch of them and are generally super-smart and knowledgeable when it comes to OpenID, so they'd probably make a good resource if you need help here.
- 在许多流行的编程语言中,已经有了OpenID库,它们将为您完成几乎所有繁重的工作。JanRain的团队写了一堆,在OpenID方面,他们通常都非常聪明和博学,所以如果你需要帮助,他们可能会成为一个很好的资源。
- Depending on the library, you may need to provide a persistent store for associations with OpenID provider sites. Essentially this is just storing a mapping from a server/handle string to an association string. You'll need to store the association at least for the session (to verify an OpenID authentication) but ideally you should store them longer so you won't have to re-associate every time you redirect to the OpenID provider (doing so will result in a faster redirect). You can use memcached, a database, or any other persistent storage medium you have access to.
- 根据库的不同,您可能需要为与OpenID提供程序站点的关联提供一个持久存储。本质上,这只是存储从服务器/句柄字符串到关联字符串的映射。您至少需要为会话存储关联(以验证OpenID身份验证),但理想情况下,您应该将它们存储得更久,以便在每次重定向到OpenID提供程序时不必重新关联(这样做将导致更快的重定向)。可以使用memcached、数据库或任何其他可访问的持久性存储介质。
- Use a schema like this (this will work with MySQL, but you may have to tweak it slightly if you use a different database or if you represent your internal user IDs differently):
create table user_openids ( openid_url varchar(255) not null, primary key (openid_url), user_id int not null, index (user_id) );
- 使用这样的模式(这将适用于MySQL,但是如果使用不同的数据库或表示内部用户id不同,您可能需要稍微调整它):创建表user_openid (
- Keep a single global table so you can use it to look up OpenIDs for all your users (even if you have your users partitioned into multiple databases).
- 保留一个全局表,以便您可以使用它查找所有用户的openid(即使您将用户划分为多个数据库)。
- Store OpenID URLs in canonicalized form for robust lookup (i.e. so if users enter their OpenID slightly differently next time, you can still map it to their account). Most OpenID libraries will provide a canonicaliztion function, but briefly you should add http:// if it's missing and you should convert the protocol and domain to lowercase (but NOT the rest of the URL), so e.g. "WWW.AOL.COM/myOpenID" should be stored as "http://www.aol.com/myOpenID". You should also probably remove any trailing slashes from the URL.
- 在规范化表单中存储OpenID url以进行健壮的查找(也就是说,如果用户下一次输入的OpenID略有不同,您仍然可以将其映射到他们的帐户)。大多数OpenID库将提供一个canonicaliztion函数,但如果缺少http://,您应该简单地添加它,并将协议和域转换为小写(而不是URL的其余部分),例如。“WWW.AOL。应将myopenid存储为http://www.aol.com/myOpenID。您还应该从URL中删除任何尾斜杠。
- If you usually have a layer of database-access code, you should expose the following functions to your application (in each case I've sketched the SQL to implement the function). As a reminder, all functions that take an OpenID as input should canonicalize it prior to looking it up in the database.
-
GetUserId(openid_url)
select user_id from user_openids where openid_url = openid_url
- GetUserId(openid_url)从user_openid中选择user_id,其中openid_url = openid_url
-
GetOpenIDsByUser(user_id)
select openid_url from user_openids where user_id = user_id
- GetOpenIDsByUser(user_id)从user_openid中选择openid_url,其中user_id = user_id
-
AttachOpenID(openid_url, user_id)
insert into user_openids values (openid_url, user_id)
- 将AttachOpenID(openid_url, user_id)插入到user_openids值(openid_url, user_id)
-
DetachOpenID(openid_url, user_id)
delete from user_openids where openid_url = openid_url and user_id = user_id
- DetachOpenID(openid_url, user_id)从user_openid中删除,其中openid_url = openid_url, user_id = user_id
-
DetachOpenIDsByUser(user_id)
delete from user_openids where user_id = user_id
- DetachOpenIDsByUser(user_id)从user_openid中删除,其中user_id = user_id
-
GetUserId(openid_url)
- 如果您通常有一层数据库访问代码,那么您应该向您的应用程序公开以下函数(在每个例子中,我已经简要介绍了实现该函数的SQL)。作为提醒,所有将OpenID作为输入的函数都应该在数据库中查找之前将其规范化。GetUserId(openid_url)从user_openid中选择user_id,其中openid_url = openid_url GetOpenIDsByUser(user_id)从user_openid = user_user_attachopenid (user_url, user_user_user_id, user_user_user_userid)插入到open_openid值中
- Add a section to your registration page where OpenID users can sign up using their OpenID. The UI goal should be that OpenID users can easily identify that your site supports OpenID, but that users without OpenID can continue to register normally without being confused. You can either put an OpenID input box directly on the page or link to an OpenID page where users can enter their OpenID.
- 在您的注册页面中添加一个部分,OpenID用户可以使用他们的OpenID注册。用户界面的目标应该是,OpenID用户可以很容易地识别出您的站点支持OpenID,但是没有OpenID的用户可以继续正常注册而不会感到困惑。您可以将OpenID输入框直接放在页面上,也可以将链接链接到OpenID页面,用户可以在该页面输入自己的OpenID。
- Wherever you put it, you should follow the community standards for naming and styling the text field where users enter their OpenID:
- Use "openid_url" as the ID and name attributes of the text field (this will allow plug-ins to easily identify and handle OpenID input boxes across different web sites)
- 使用“openid_url”作为文本字段的ID和名称属性(这将允许插件轻松识别和处理不同web站点的OpenID输入框)
- Add the small OpenID logo as a background image to the text box, using CSS like this:
background: #FFFFFF url('/images/openid-icon-small.gif') no-repeat scroll 0pt 50%; padding-left: 18px;
- 将小的OpenID标志作为背景图像添加到文本框中,使用如下CSS: background: # ffffffffff url('/images/ OpenID -icon-small.gif')
- 无论你所说,你应该遵循社区标准命名和样式的文本框,用户输入他们的OpenID:使用“openid_url”作为ID和名称文本框的属性(这将允许插件很容易识别和处理OpenID输入框在不同网站)小OpenID标识作为背景图像添加到文本框,使用CSS:背景:# FFFFFF url(/图片/ openid-icon-small.gif)没有重演滚动0 pt 50%;
- It's also a good idea to provide a brief explanation of what OpenID is and how your users can use it on your site (since you'll probably get curious people clicking through to take a look).
- 提供一个关于OpenID是什么以及用户如何在您的站点上使用它的简短说明也是一个好主意(因为您可能会让好奇的人点击查看)。
- Wrap the OpenID text box in a form that will submit to your OpenID login CGI, which we'll build below.
- 将OpenID文本框包装成提交给您的OpenID登录CGI的表单,我们将在下面构建这个表单。
- Upon providing an OpenID and signing in to the OpenID provider, you'll need to redirect your user back to your registration page with a couple of small tweaks. First, you should show the OpenID that the user is registering with, preferably with the small OpenID logo next to it to consistently identify it as an OpenID (see the screenshots below for an example). Second, you should NOT ask the user for a site-specific password, since they'll be signing in with their OpenID. So hide the password fields and make sure your registration code will allow this (you may need to stick in a random password behind the scenes if your code requires some password text, just don't show it to the user). [Note: it's fine to let users enter a site-specific password later by using your account settings page, but the point here is that one of the major benefits you're providing OpenID users is that they no longer need to maintain separate credentials for each site they use.]
- 在提供一个OpenID并登录到OpenID提供程序之后,您需要通过几个小的调整将用户重定向回注册页面。首先,您应该显示用户正在注册的OpenID,最好是在它旁边有一个小的OpenID标识,以便始终将其标识为OpenID(参见下面的屏幕截图)。其次,您不应该向用户询问特定于站点的密码,因为他们将使用自己的OpenID登录。因此,隐藏密码字段并确保注册码允许这样做(如果您的代码需要一些密码文本,您可能需要在后台输入一个随机密码,但不要向用户显示)。[注意:允许用户稍后使用您的帐户设置页面输入特定于站点的密码是可以的,但这里的要点是,您为OpenID用户提供的主要好处之一是,他们不再需要为他们使用的每个站点维护单独的凭据。]
- Here are some screenshots of how we added OpenID to Plaxo's registration flow:
- 以下是我们如何在Plaxo的注册流中添加OpenID的一些截图:
- Add a section to your signin page where OpenID users can sign in using their OpenID. This will work both for existing users of your site that have attached an OpenID to their account and new users, who will be able to sign up using their OpenID (using the same flow as above). Like with the registration page, the UI goal should be a balance between being obvious to OpenID users without overly distracting or confusing the rest of your users. You should name and style your OpenID box as specified above in the registration page. And like above, the form surrounding the OpenID input box should go to the OpenID login CGI you're about to build.
- 在您的登录页面中添加一个部分,OpenID用户可以使用他们的OpenID登录。这既适用于已将OpenID附加到其帐户的现有用户,也适用于新用户,新用户可以使用自己的OpenID注册(使用与上面相同的流)。与注册页面一样,UI的目标应该是在对OpenID用户明显而不过分分散或混淆其他用户之间取得平衡。您应该在注册页面中指定的名称和样式设置您的OpenID框。和上面一样,围绕OpenID输入框的表单应该指向即将构建的OpenID登录CGI。
- In addition to your main signin page, you may also have signin UI in your home page or elsewhere. You should ideally provide an option to sign in using OpenID in every place you provide a traditional signin option.
- 除了主登录页面之外,您的主页或其他地方也可能有登录UI。理想情况下,您应该在提供传统登录选项的每个地方提供使用OpenID登录的选项。
- Here are some screenshots of how we added OpenID to Plaxo's signin pages:
- 以下是我们如何将OpenID添加到Plaxo登录页面的一些截图:
- Your CGI should take two basic input (query) parameters:
- openid_url: the OpenID entered by the user (for registration, signin, attaching, etc.)
- openid_url:用户输入的OpenID(用于注册、登录、附加等)。
- action_type: the operation the user wants to perform. Possible values will be login, complete, attach, list, and delete. (If you're using Rails or a similar system, these could also be controller methods and thus part of the URL itself.)
- action_type:用户想要执行的操作。可能的值是登录、完成、附加、列表和删除。(如果您正在使用Rails或类似的系统,这些也可以是控制器方法,因此是URL本身的一部分。)
- 您的CGI应该接受两个基本的输入(查询)参数:openid_url:用户输入的OpenID(用于注册、登录、附加等)action_type:用户想要执行的操作。可能的值是登录、完成、附加、列表和删除。(如果您正在使用Rails或类似的系统,这些也可以是控制器方法,因此是URL本身的一部分。)
- Implement the login action (this is where the UI you added to the registration and signin flows will both submit to)
- 实现登录操作(这是您添加到注册和登录流的UI都要提交的地方)
- Look up the provided openid_url using the GetUserId function described above.
- 使用上面描述的GetUserId函数查找提供的openid_url。
- If the OpenID is already attached to a user in your system, check to see if the user is currently signed in to your site.
- 如果OpenID已经连接到系统中的用户,请检查用户是否已经登录到您的站点。
- If the user is not signed in, they are attempting to sign in as an existing user, so prepare to redirect to their OpenID provider, but set a flag to NOT ask the provider for registration info (since the user is not signing up for a new account).
- 如果用户没有登录,他们将尝试以现有用户的身份登录,因此准备重定向到他们的OpenID提供程序,但是设置一个标记,不向提供程序请求注册信息(因为用户没有注册新帐户)。
- If the user is already signed in, and this OpenID already belongs to them (i.e. the OpenID URL is mapped to the same user_id as the currently signed-in user), then you don't have to do anything (this user is already signed in and already attached that OpenID, so this is a no-op). This is an edge case.
- 如果用户已经登录,这OpenID已经属于他们(比如OpenID URL映射到相同的user_id当前登录用户),那么你不需要做任何事(这个用户已经签署了在OpenID和已连接,这是一个空操作)。这是一个边缘情况。
- If the user is already signed in but the OpenID belongs to a different user, show an error message saying that this OpenID has already been claimed by another user. You can also provide the user the option to sign out and try again. This is an edge case.
- 如果用户已经签入,但OpenID属于不同的用户,则显示一条错误消息,说明该OpenID已被另一个用户声明。您还可以向用户提供退出和重试的选项。这是一个边缘情况。
- If the OpenID is NOT currently in your database, the user is trying to sign up for a new account, so prepare to redirect to their OpenID provider and ask for registration info.
- 如果OpenID目前不在您的数据库中,那么用户正在尝试注册一个新帐户,所以准备重定向到他们的OpenID提供程序并询问注册信息。
- Save the provided openid_url in your session, since you'll need it to remember it when the OpenID provider redirects back to you, and the provider may not return it to you. If you don't have a session, you can use your database, but it has to be somewhere persistent and protected from user-tampering (i.e. not in a cookie or something that could be changed or forged by the user).
(The reason you need to store the requested OpenID is that OpenID lets users delegate their OpenID to another provider behind-the-scenes. For instance, if I try to sign up with the OpenID josephsmarr.com, I may have actually delegated that URL to a different OpenID like jsmarr.myopenid.com, and when the provider returns to you to complete authentication, you need to remember that I wanted to sign up as josephsmarr.com and not jsmarr.myopenid.com. Luckily your OpenID library will most likely handle this for you, but you still have to keep the originally requested OpenID in your session for now. This may be solved in the upcoming OpenID 2.0 spec.) - 将提供的openid_url保存在会话中,因为当OpenID提供程序重定向给您时,您需要它记住它,而提供程序可能不会将它返回给您。如果你没有会话,你可以使用你的数据库,但是它必须是一个持久的并且保护不受用户篡改的地方(例如,不在一个cookie或者其他可以被用户修改或伪造的东西中)。(需要存储所请求的OpenID的原因是,OpenID允许用户将其OpenID委托给另一个提供者。例如,如果我尝试注册OpenID josephsmarr.com,我可能已经将该URL委托给了另一个OpenID,比如jsmarr.myopenid.com,当提供者返回给您完成身份验证时,您需要记住我想注册为josephsmarr.com而不是jsmarr.myopenid.com。幸运的是,您的OpenID库很可能会为您处理这个问题,但是您仍然需要将最初请求的OpenID保存在会话中。这可以在即将发布的OpenID 2.0规范中解决)。
- Construct your return_to URL for the OpenID provider to return to after the user has authenticated. This will be your OpenID login CGI with the complete action specified.
- 构造return_to URL,以便OpenID提供程序在用户验证后返回。这将是您的OpenID登录CGI,并指定完整的操作。
- If you've determined above that the user is registering for a new account, decide what registration info to ask for. Most OpenID providers support the simple-registration extension, which is a list of common registration fields that you can request as required or optional for your site, including full name, e-mail, nickname, gender, date of birth, gender, postal code, country, language, and time zone. If you ask for these fields and the user consents to provide them, you can pre-fill them into your registration flow, thus removing time and friction from your registration process. If your OpenID consumer library doesn't natively support requesting simple-registration parameters, see if they have a general facility for supporting extensions, or worst-case you can manually add it to the generated redirect URL before redirecting.
- 如果您在上面确定用户正在注册一个新帐户,请决定需要什么注册信息。大多数OpenID提供程序都支持简单注册扩展,这是一个公共注册字段列表,您可以根据需要或可选地对您的站点进行请求,包括全名、电子邮件、昵称、性别、出生日期、性别、邮政编码、国家、语言和时区。如果您请求这些字段,并且用户同意提供这些字段,您可以将它们预填充到注册流中,从而消除注册过程中的时间和摩擦。如果您的OpenID使用者库本身不支持请求简单注册参数,请查看它们是否具有支持扩展的通用功能,或者最坏的情况是,您可以在重定向之前将其手动添加到生成的重定向URL。
- Call checkid_setup in your OpenID library to generate the URL to redirect to the user's OpenID provider. Pass in the (canonicalized) OpenID provided by the user and the return_to URL you constructed above. Also pass in the simple registration info you want if appropriate. Depending on your library, you may need to trap and handle some errors from this function. But assuming everything goes well, it will give you back a URL to redirect to.
- 调用OpenID库中的checkid_setup来生成URL以重定向到用户的OpenID提供程序。传递用户提供的(规范化的)OpenID和上面构造的return_to URL。如果合适的话,也要传递你想要的简单注册信息。根据您的库,您可能需要捕获并处理这个函数中的一些错误。但如果一切顺利,它将返回一个URL以重定向到。
- Have your CGI redirect to the provided URL, ideally by issuing a server-side redirect response.
- 让您的CGI重定向到所提供的URL,最好是通过发出服务器端重定向响应。
- The user will be redirected to their OpenID provider's web site. They will be asked to sign in (unless they've recently signed in there), they will be asked whether they trust your web site, and if you've asked for simple registration info, they'll be asked what info they want to share with you. Once they complete this process, the OpenID provider will redirect the user back to the return_to URL you supplied, which will then let you initiate your complete action to finish the job.
Here are some screenshots of signing into an OpenID provider (myopenid.com in this case) and being prompted to share some registration info with Plaxo:
- 用户将被重定向到他们的OpenID提供者的网站。他们会被要求签到(除非他们最近在那里签到),他们会被问他们是否信任你的网站,如果你问他们简单的注册信息,他们会被问他们想和你分享什么信息。一旦他们完成了这个过程,OpenID提供程序就会将用户重定向回您提供的return_to URL,然后您就可以启动完整的操作来完成任务。下面是一些登录到OpenID提供商(这里是myopenid.com)并被提示与Plaxo分享一些注册信息的截图:
- When the OpenID provider redirects to your return_to URL, they will add a bunch of additional query string parameters that contain the information needed to verify the user's authentication with this OpenID. Depending on the OpenID library you're using, you may need to gather these up into a data structure to pass in to the verification function, or it may do it for you.
- 当OpenID提供程序重定向到return_to URL时,它们将添加一些附加的查询字符串参数,这些参数包含使用这个OpenID验证用户身份所需的信息。根据您正在使用的OpenID库,您可能需要将它们收集到一个数据结构中,以便传递给验证函数,或者它可以为您这样做。
- Get the OpenID the user initially requested from your session (you stored it before redirecting to the OpenID provider above).
- 获取用户最初从会话中请求的OpenID(您在重定向到上面的OpenID提供程序之前存储了它)。
- Call id_res in your OpenID library to verify the authentication data you've been sent by the OpenID provider. Pass in the OpenID that the user initially requested, along with the query parameters as needed. This function will check to see if everything looks valid. If you get an error back, display an appropriate error message to your user. Otherwise you've now confirmed that the user has authenticated the OpenID they provided to you.
- 在OpenID库中调用id_res,以验证OpenID提供者发送的身份验证数据。输入用户最初请求的OpenID,以及需要的查询参数。这个函数将检查是否一切都是有效的。如果返回错误,请向用户显示适当的错误消息。否则,您现在已经确认用户已经验证了他们提供给您的OpenID。
- Optional: after successfully verifying the OpenID, you may wish to set a persistent cookie for your site with the OpenID used so that you can recognize that the user has an OpenID next time they come to your site and pre-fill the OpenID box on the signin page. If you do this, make sure to also clear the cookie when the user explicitly signs out.
- 可选:在成功验证OpenID之后,您可能希望使用OpenID为您的站点设置一个持久cookie,以便在用户下次访问您的站点并在登录页面上预填充OpenID框时,您可以识别用户有一个OpenID。如果这样做,请确保在用户显式退出时也清除cookie。
- Look up the verified OpenID again using the GetUserId function. If you don't find it in your database, check to see if the user is currently signed in on your site. If they are, perform the attach action below to attach this OpenID to their existing account. Otherwise, it's time to start the registration process for a new account using this OpenID. Start by storing the verified OpenID in your session so your account creation code will remember the user has already verified this OpenID. (Do NOT use the same session variable you used to store the requested OpenID, since the user can type in anything there.)
Then redirect your user to your registration flow and pass along the simple registration data you got back (if any). You will probably have to map the fields returned by simple-registration to the registration parameters that your site normally takes.- As described above, the registration page should show the OpenID prominently in the account information, and you should NOT ask the user to enter a password for your site, since they'll be using their OpenID to sign in. In addition, you should pre-fill any registration info provided from their OpenID provider. It is fine to ask for additional registration info and maintain your current policies about which fields are required and optional. (Using OpenID should be an acceleration for registering on your site, but should not require you to change what information you require or otherwise change your site's normal behavior). Finally, you should provide a link for existing users of your service to attach this OpenID to their existing account, if they have one. This will handle the case of existing users that weren't signed in and entered their OpenID and have no found themselves in the new-user registration flow. [Since this isn't common, it's better to just have a small link at the beginning of the registration flow rather than asking every user "do you want to register a new account or sign in to an existing account" when they first verify their OpenID.]
- 如上所述,注册页面应该在帐户信息的显著位置显示OpenID,并且您不应该要求用户为您的站点输入密码,因为他们将使用他们的OpenID登录。此外,您应该预先填写从他们的OpenID提供程序提供的任何注册信息。可以询问额外的注册信息并维护您当前的策略,了解哪些字段是必需的和可选的。(使用OpenID应该是站点注册的加速,但不应该要求您更改您需要的信息或更改站点的正常行为)。最后,您应该为服务的现有用户提供一个链接,以便将这个OpenID附加到他们现有的帐户(如果他们有的话)。这将处理未登录并输入OpenID且在新用户注册流中没有找到自己的现有用户的情况。[因为这并不常见,所以最好在注册流开始时使用一个小链接,而不是在用户第一次验证OpenID时问每个用户“您想注册一个新帐户还是登录到现有帐户”。]
- When the user completes your site's registration flow and you create a user account, attach the verified OpenID to the newly created account using your AttachOpenID function. [If your user table and OpenID table are in separate databases and cannot be part of the same transaction, there is a small chance that the attach command could fail and leave you with an orphaned user account. There's no easy way to prevent this in 100% of cases, but since it's rare and the user can always sign up again, in most cases you can ignore this race condition and just hope for the best.
- 当用户完成您的站点注册流程并创建用户帐户时,使用您的AttachOpenID函数将验证的OpenID附加到新创建的帐户。[如果您的用户表和OpenID表位于独立的数据库中,并且不能属于同一事务,那么attach命令可能会失败,并留给您一个孤立的用户帐户。在100%的情况下,没有简单的方法可以防止这种情况发生,但是由于这种情况很少见,而且用户总是可以再次注册,所以在大多数情况下,您可以忽略这种竞争状况,只希望得到最好的结果。
- 使用GetUserId函数再次查找已验证的OpenID。如果在数据库中找不到,请检查用户是否正在您的站点上签名。如果是,执行下面的attach操作,将这个OpenID附加到现有帐户。否则,就该使用这个OpenID启动新帐户的注册过程了。首先在会话中存储已验证的OpenID,这样您的帐户创建代码就会记住用户已经验证了这个OpenID。(不要使用您用来存储所请求的OpenID的相同会话变量,因为用户可以在其中输入任何内容。)然后将用户重定向到注册流,并传递返回的简单注册数据(如果有的话)。您可能需要将简单注册返回的字段映射到站点通常需要的注册参数。如上所述,注册页面应该在帐户信息的显著位置显示OpenID,并且您不应该要求用户为您的站点输入密码,因为他们将使用他们的OpenID登录。此外,您应该预先填写从他们的OpenID提供程序提供的任何注册信息。可以询问额外的注册信息并维护您当前的策略,了解哪些字段是必需的和可选的。(使用OpenID应该是站点注册的加速,但不应该要求您更改您需要的信息或更改站点的正常行为)。最后,您应该为服务的现有用户提供一个链接,以便将这个OpenID附加到他们现有的帐户(如果他们有的话)。这将处理未登录并输入OpenID且在新用户注册流中没有找到自己的现有用户的情况。因为这并不常见,所以最好在注册流开始时使用一个小链接,而不是在用户第一次验证OpenID时问每个用户“您想注册一个新帐户还是登录到现有帐户”。当用户完成站点注册流程并创建用户帐户时,使用AttachOpenID函数将已验证的OpenID附加到新创建的帐户。[如果您的用户表和OpenID表位于独立的数据库中,并且不能属于同一事务,那么attach命令可能会失败,并留给您一个孤立的用户帐户。在100%的情况下,没有简单的方法可以防止这种情况发生,但是由于这种情况很少见,而且用户总是可以再次注册,所以在大多数情况下,您可以忽略这种竞争状况,只希望得到最好的结果。
- If you found that the verified OpenID was attached to an existing account, you can now sign the user in as you normally would if they'd signed in through your traditional method. (If the user happens to be signed in to a different account, sign them out and then sign them in as the user the OpenID is attached to, since they just proved they own it).
- 如果您发现已验证的OpenID附加到一个现有的帐户,您现在可以像往常一样在用户通过传统方法登录时进行签名。(如果用户碰巧登录到另一个帐户,那么将其签名,然后作为OpenID的附加用户签名,因为他们刚刚证明自己拥有该帐户)。
Here's a screenshot of Plaxo's attach confirmation page:
- Require the user to be signed in (redirect through your signin page first if needed).
- 要求用户登录(如果需要的话,请先重定向登录您的登录页面)。
- Fetch the list of attached OpenIDs for the signed-in user by calling your GetOpenIDsByUser function.
- 通过调用GetOpenIDsByUser函数来获取已注册用户的附加openid列表。
- Show the list of OpenIDs in a web page with a link by each one to detach it if the user wants. The links will call the delete action below and pass in the OpenID to delete as the openid_url parameter.
- 在web页面中显示openid列表,每个页面都有一个链接,以便在用户需要时将其分离。链接将调用下面的delete操作,并将OpenID作为openid_url参数传递给delete。
- Provide a link or input box to attach an additional OpenID. This will take the user through the login and attach flows (since the user is already signed in) and end up back on the list page.
- 提供附加的OpenID的链接或输入框。这将使用户通过登录和附加流(因为用户已经登录)并返回到列表页面。
- If your site already has a general settings page, you should provide a link to "Manage your OpenIDs" that links to this list page. You may also decide to build this functionality directly into your current settings page.
Here's a screenshot of Plaxo's list page, as well as links to it from our current settings pages:
- 如果你的站点已经有一个通用设置页面,你应该提供一个链接来“管理你的openid”,链接到这个列表页面。您还可以决定将此功能直接构建到当前设置页面中。这里是Plaxo的列表页面的截图,以及我们当前设置页面的链接:
- Require the user to be signed in (redirect through your signin page first if needed).
- 要求用户登录(如果需要的话,请先重定向登录您的登录页面)。
- Optional: Check whether the user is trying to delete the last credential they could use to sign in to your site. If the user has not set up a normal password on your site and this is the only OpenID attached to their account, deleting their last OpenID would essentially lock them out of their account forever. If you don't have a good way to recover users in this situation, show an error message if the user tries to delete their last attached credential, saying essentially "You can't delete the last OpenID attached to your account because you'd have no way to sign in. First attach another OpenID or create a password for this site."
- 可选:检查用户是否试图删除他们可以用来登录到您的站点的最后凭据。如果用户没有在您的站点上设置一个普通的密码,并且这是唯一一个附加到他们的帐户上的OpenID,删除他们的最后一个OpenID将基本上永远锁在他们的帐户之外。如果您在这种情况下没有很好的方法来恢复用户,如果用户试图删除他们最后的附加凭证,显示一条错误消息,本质上说“您不能删除附加到您的帐户上的最后一个OpenID,因为您没有办法登录。”首先附加一个OpenID或为这个站点创建一个密码。
- Assuming it's ok to proceed, detach the OpenID provided by the openid_url parameter from the signed-in user's account by calling your DetachOpenID function. If the OpenID provided is not currently attached to the user's account, you can choose to show an error or just treat it as a no-op success.
- 假设可以继续,那么通过调用DetachOpenID函数将openid_url参数提供的OpenID从注册用户的帐户中分离出来。如果提供的OpenID目前没有附加到用户的帐户上,您可以选择显示错误或将其视为无操作成功。
- Show a confirmation message that this OpenID has now been detached and can no longer be used to sign in to your site. Tell the user that if they want to re-attach this OpenID, they will have to go through the normal verification process to re-attach it. Consider redirecting to the list action so the user can see the updated list of OpenIDs attached to their account.
Here are some screenshots of detaching an OpenID from a Plaxo account:
- 显示一个确认消息,这个OpenID现在已经被分离,不能再用于登录您的站点。告诉用户,如果他们想重新连接这个OpenID,他们必须通过正常的验证过程才能重新连接它。考虑重定向到list操作,以便用户可以看到附加到其帐户的更新的openid列表。下面是一些从Plaxo账户中分离OpenID的截图:
- If your site currently lets users delete their accounts, it's important that you also detach any OpenIDs that were attached so they can be re-attached to another account later. You can do this by calling your DetachOpenIDsByUser function inside your delete-user routine, or by otherwise triggering this function when deleting a user.
- 如果您的站点目前允许用户删除他们的帐户,那么重要的是您也要分离任何附加的openid,以便以后可以将它们重新附加到另一个帐户。您可以通过在删除用户例程中调用DetachOpenIDsByUser函数来实现这一点,或者在删除用户时触发此函数。
...and you're done!
Snipped.. so check the wayback machine link up above for the rest. Joseph goes through some best practices for OpenID, but at this point you should have a working example.
剪掉. .因此,请检查上面的wayback机器连接到上面的其他部分。Joseph介绍了OpenID的一些最佳实践,但是现在您应该有一个可用的示例。
#1
12
Since this is one of the top search results when searching for OpenID Database Structures on Google, and the Plaxo link referenced in the previous answer is no longer around. I've copied and pasted the content of the Plaxo instructions below. I was able to get them by using the wayback machine page referenced here. Keep in mind that because of *'s 30000 character restrictions, I will have to crop certain sections, and Joseph Smarr included some images in his instructions, so you might want to look at the wayback machine page I referenced. -Jason
因为在谷歌上搜索OpenID数据库结构时,这是最重要的搜索结果之一,并且前面的答案中引用的Plaxo链接已经不复存在。我已经复制粘贴了下面Plaxo指令的内容。我可以使用这里引用的wayback机器页面来获得它们。请记住,由于*的3万个字符限制,我将不得不裁剪某些部分,而Joseph Smarr在他的指令中包含了一些图像,所以您可能想要查看我引用的wayback machine页面。杰森
A Recipe for OpenID-Enabling Your Site
Prepared by Joseph Smarr at Plaxo on July 18, 2007.
2007年7月18日,约瑟夫·斯玛在Plaxo编写。
This is a step-by-step tutorial guide for implementing OpenID consumer-side support with a web site that already has users with accounts. It will explain how to easily let new users sign up for an account on your site using their OpenID URL and how to let existing users attach their OpenID(s) so they can sign in using them.
这是一个循序渐进的教程指南,用于实现OpenID客户端支持,该网站已经拥有帐户用户。它将解释如何方便地让新用户使用他们的OpenID URL注册您的站点上的一个帐户,以及如何让现有用户附加他们的OpenID,以便他们可以使用它们登录。
I developed this guide by talking to fellow OpenID developers at the Internet Identity Workshop and elsewhere, and by implementing OpenID support for Plaxo using these instructions. I've also posted detailed screenshots of Plaxo's implementation for reference. I've intended for this guide to be clear and complete and to follow best-practices, but if you have any questions or feedback, please let me know at ob_male('joseph','plaxo.com'); or by posting a comment on Plaxo's blog.
我在Internet Identity研讨会和其他地方与OpenID开发人员进行了交谈,并使用这些说明实现了对Plaxo的OpenID支持。我还发布了Plaxo的实现的详细截图,以供参考。我希望本指南清晰完整,并遵循最佳实践,但如果您有任何问题或反馈,请在ob_male('joseph','plaxo.com')让我知道;或者在Plaxo的博客上发表评论。
This guide may look a bit long, but my hope is you can just follow it straight through without thinking much, and you'll be completely done by the time you reach the end! :)
这个指南可能看起来有点长,但我希望你可以直接按照它进行,而不需要想太多,你将完全完成,当你到达终点!:)
Overview
I'm assuming your web site currently has:
我假设你的网站目前有:
- A user database with rows for each user
- Each user has a unique internal user ID
- 每个用户都有一个惟一的内部用户ID。
- Users currently sign in using a username/e-mail and password
- 用户目前使用用户名/电子邮件和密码登录
- 一个用户数据库中,每个用户都有一个唯一的内部用户ID,用户当前使用用户名/电子邮件和密码进行签名
- A registration flow for signing up new users and getting collecting basic profile info
- 注册流程,用于注册新用户并获取基本的配置信息
- A signin page for authenticating users
- Internally you authenticate users based on username/e-mail and password, look up their unique user ID, and use it in the rest of your site
- 在内部,您根据用户名/电子邮件和密码对用户进行身份验证,查找他们的唯一用户ID,并在站点的其他部分使用它
- 用户身份验证的登录页面,您可以基于用户名/电子邮件和密码对用户进行身份验证,查找他们的唯一用户ID,并在站点的其他部分使用它
- A settings page for users to manage their account info.
- 用户管理帐户信息的设置页面。
If your site doesn't look like this, you should still be able to follow along, but some of the sections may not be relevant to you.
如果你的网站看起来不像这样,你仍然可以跟随,但是有些部分可能与你无关。
Snipped.. so check the wayback machine link up above for the rest.
剪掉. .所以,请查看上面的回程机链接。
Implementation details
- There are OpenID libraries already available in many popular programming languages that will do almost all of the heavy lifting for you. The team at JanRain wrote a bunch of them and are generally super-smart and knowledgeable when it comes to OpenID, so they'd probably make a good resource if you need help here.
- 在许多流行的编程语言中,已经有了OpenID库,它们将为您完成几乎所有繁重的工作。JanRain的团队写了一堆,在OpenID方面,他们通常都非常聪明和博学,所以如果你需要帮助,他们可能会成为一个很好的资源。
- Depending on the library, you may need to provide a persistent store for associations with OpenID provider sites. Essentially this is just storing a mapping from a server/handle string to an association string. You'll need to store the association at least for the session (to verify an OpenID authentication) but ideally you should store them longer so you won't have to re-associate every time you redirect to the OpenID provider (doing so will result in a faster redirect). You can use memcached, a database, or any other persistent storage medium you have access to.
- 根据库的不同,您可能需要为与OpenID提供程序站点的关联提供一个持久存储。本质上,这只是存储从服务器/句柄字符串到关联字符串的映射。您至少需要为会话存储关联(以验证OpenID身份验证),但理想情况下,您应该将它们存储得更久,以便在每次重定向到OpenID提供程序时不必重新关联(这样做将导致更快的重定向)。可以使用memcached、数据库或任何其他可访问的持久性存储介质。
- Use a schema like this (this will work with MySQL, but you may have to tweak it slightly if you use a different database or if you represent your internal user IDs differently):
create table user_openids ( openid_url varchar(255) not null, primary key (openid_url), user_id int not null, index (user_id) );
- 使用这样的模式(这将适用于MySQL,但是如果使用不同的数据库或表示内部用户id不同,您可能需要稍微调整它):创建表user_openid (
- Keep a single global table so you can use it to look up OpenIDs for all your users (even if you have your users partitioned into multiple databases).
- 保留一个全局表,以便您可以使用它查找所有用户的openid(即使您将用户划分为多个数据库)。
- Store OpenID URLs in canonicalized form for robust lookup (i.e. so if users enter their OpenID slightly differently next time, you can still map it to their account). Most OpenID libraries will provide a canonicaliztion function, but briefly you should add http:// if it's missing and you should convert the protocol and domain to lowercase (but NOT the rest of the URL), so e.g. "WWW.AOL.COM/myOpenID" should be stored as "http://www.aol.com/myOpenID". You should also probably remove any trailing slashes from the URL.
- 在规范化表单中存储OpenID url以进行健壮的查找(也就是说,如果用户下一次输入的OpenID略有不同,您仍然可以将其映射到他们的帐户)。大多数OpenID库将提供一个canonicaliztion函数,但如果缺少http://,您应该简单地添加它,并将协议和域转换为小写(而不是URL的其余部分),例如。“WWW.AOL。应将myopenid存储为http://www.aol.com/myOpenID。您还应该从URL中删除任何尾斜杠。
- If you usually have a layer of database-access code, you should expose the following functions to your application (in each case I've sketched the SQL to implement the function). As a reminder, all functions that take an OpenID as input should canonicalize it prior to looking it up in the database.
-
GetUserId(openid_url)
select user_id from user_openids where openid_url = openid_url
- GetUserId(openid_url)从user_openid中选择user_id,其中openid_url = openid_url
-
GetOpenIDsByUser(user_id)
select openid_url from user_openids where user_id = user_id
- GetOpenIDsByUser(user_id)从user_openid中选择openid_url,其中user_id = user_id
-
AttachOpenID(openid_url, user_id)
insert into user_openids values (openid_url, user_id)
- 将AttachOpenID(openid_url, user_id)插入到user_openids值(openid_url, user_id)
-
DetachOpenID(openid_url, user_id)
delete from user_openids where openid_url = openid_url and user_id = user_id
- DetachOpenID(openid_url, user_id)从user_openid中删除,其中openid_url = openid_url, user_id = user_id
-
DetachOpenIDsByUser(user_id)
delete from user_openids where user_id = user_id
- DetachOpenIDsByUser(user_id)从user_openid中删除,其中user_id = user_id
-
GetUserId(openid_url)
- 如果您通常有一层数据库访问代码,那么您应该向您的应用程序公开以下函数(在每个例子中,我已经简要介绍了实现该函数的SQL)。作为提醒,所有将OpenID作为输入的函数都应该在数据库中查找之前将其规范化。GetUserId(openid_url)从user_openid中选择user_id,其中openid_url = openid_url GetOpenIDsByUser(user_id)从user_openid = user_user_attachopenid (user_url, user_user_user_id, user_user_user_userid)插入到open_openid值中
- Add a section to your registration page where OpenID users can sign up using their OpenID. The UI goal should be that OpenID users can easily identify that your site supports OpenID, but that users without OpenID can continue to register normally without being confused. You can either put an OpenID input box directly on the page or link to an OpenID page where users can enter their OpenID.
- 在您的注册页面中添加一个部分,OpenID用户可以使用他们的OpenID注册。用户界面的目标应该是,OpenID用户可以很容易地识别出您的站点支持OpenID,但是没有OpenID的用户可以继续正常注册而不会感到困惑。您可以将OpenID输入框直接放在页面上,也可以将链接链接到OpenID页面,用户可以在该页面输入自己的OpenID。
- Wherever you put it, you should follow the community standards for naming and styling the text field where users enter their OpenID:
- Use "openid_url" as the ID and name attributes of the text field (this will allow plug-ins to easily identify and handle OpenID input boxes across different web sites)
- 使用“openid_url”作为文本字段的ID和名称属性(这将允许插件轻松识别和处理不同web站点的OpenID输入框)
- Add the small OpenID logo as a background image to the text box, using CSS like this:
background: #FFFFFF url('/images/openid-icon-small.gif') no-repeat scroll 0pt 50%; padding-left: 18px;
- 将小的OpenID标志作为背景图像添加到文本框中,使用如下CSS: background: # ffffffffff url('/images/ OpenID -icon-small.gif')
- 无论你所说,你应该遵循社区标准命名和样式的文本框,用户输入他们的OpenID:使用“openid_url”作为ID和名称文本框的属性(这将允许插件很容易识别和处理OpenID输入框在不同网站)小OpenID标识作为背景图像添加到文本框,使用CSS:背景:# FFFFFF url(/图片/ openid-icon-small.gif)没有重演滚动0 pt 50%;
- It's also a good idea to provide a brief explanation of what OpenID is and how your users can use it on your site (since you'll probably get curious people clicking through to take a look).
- 提供一个关于OpenID是什么以及用户如何在您的站点上使用它的简短说明也是一个好主意(因为您可能会让好奇的人点击查看)。
- Wrap the OpenID text box in a form that will submit to your OpenID login CGI, which we'll build below.
- 将OpenID文本框包装成提交给您的OpenID登录CGI的表单,我们将在下面构建这个表单。
- Upon providing an OpenID and signing in to the OpenID provider, you'll need to redirect your user back to your registration page with a couple of small tweaks. First, you should show the OpenID that the user is registering with, preferably with the small OpenID logo next to it to consistently identify it as an OpenID (see the screenshots below for an example). Second, you should NOT ask the user for a site-specific password, since they'll be signing in with their OpenID. So hide the password fields and make sure your registration code will allow this (you may need to stick in a random password behind the scenes if your code requires some password text, just don't show it to the user). [Note: it's fine to let users enter a site-specific password later by using your account settings page, but the point here is that one of the major benefits you're providing OpenID users is that they no longer need to maintain separate credentials for each site they use.]
- 在提供一个OpenID并登录到OpenID提供程序之后,您需要通过几个小的调整将用户重定向回注册页面。首先,您应该显示用户正在注册的OpenID,最好是在它旁边有一个小的OpenID标识,以便始终将其标识为OpenID(参见下面的屏幕截图)。其次,您不应该向用户询问特定于站点的密码,因为他们将使用自己的OpenID登录。因此,隐藏密码字段并确保注册码允许这样做(如果您的代码需要一些密码文本,您可能需要在后台输入一个随机密码,但不要向用户显示)。[注意:允许用户稍后使用您的帐户设置页面输入特定于站点的密码是可以的,但这里的要点是,您为OpenID用户提供的主要好处之一是,他们不再需要为他们使用的每个站点维护单独的凭据。]
- Here are some screenshots of how we added OpenID to Plaxo's registration flow:
- 以下是我们如何在Plaxo的注册流中添加OpenID的一些截图:
- Add a section to your signin page where OpenID users can sign in using their OpenID. This will work both for existing users of your site that have attached an OpenID to their account and new users, who will be able to sign up using their OpenID (using the same flow as above). Like with the registration page, the UI goal should be a balance between being obvious to OpenID users without overly distracting or confusing the rest of your users. You should name and style your OpenID box as specified above in the registration page. And like above, the form surrounding the OpenID input box should go to the OpenID login CGI you're about to build.
- 在您的登录页面中添加一个部分,OpenID用户可以使用他们的OpenID登录。这既适用于已将OpenID附加到其帐户的现有用户,也适用于新用户,新用户可以使用自己的OpenID注册(使用与上面相同的流)。与注册页面一样,UI的目标应该是在对OpenID用户明显而不过分分散或混淆其他用户之间取得平衡。您应该在注册页面中指定的名称和样式设置您的OpenID框。和上面一样,围绕OpenID输入框的表单应该指向即将构建的OpenID登录CGI。
- In addition to your main signin page, you may also have signin UI in your home page or elsewhere. You should ideally provide an option to sign in using OpenID in every place you provide a traditional signin option.
- 除了主登录页面之外,您的主页或其他地方也可能有登录UI。理想情况下,您应该在提供传统登录选项的每个地方提供使用OpenID登录的选项。
- Here are some screenshots of how we added OpenID to Plaxo's signin pages:
- 以下是我们如何将OpenID添加到Plaxo登录页面的一些截图:
- Your CGI should take two basic input (query) parameters:
- openid_url: the OpenID entered by the user (for registration, signin, attaching, etc.)
- openid_url:用户输入的OpenID(用于注册、登录、附加等)。
- action_type: the operation the user wants to perform. Possible values will be login, complete, attach, list, and delete. (If you're using Rails or a similar system, these could also be controller methods and thus part of the URL itself.)
- action_type:用户想要执行的操作。可能的值是登录、完成、附加、列表和删除。(如果您正在使用Rails或类似的系统,这些也可以是控制器方法,因此是URL本身的一部分。)
- 您的CGI应该接受两个基本的输入(查询)参数:openid_url:用户输入的OpenID(用于注册、登录、附加等)action_type:用户想要执行的操作。可能的值是登录、完成、附加、列表和删除。(如果您正在使用Rails或类似的系统,这些也可以是控制器方法,因此是URL本身的一部分。)
- Implement the login action (this is where the UI you added to the registration and signin flows will both submit to)
- 实现登录操作(这是您添加到注册和登录流的UI都要提交的地方)
- Look up the provided openid_url using the GetUserId function described above.
- 使用上面描述的GetUserId函数查找提供的openid_url。
- If the OpenID is already attached to a user in your system, check to see if the user is currently signed in to your site.
- 如果OpenID已经连接到系统中的用户,请检查用户是否已经登录到您的站点。
- If the user is not signed in, they are attempting to sign in as an existing user, so prepare to redirect to their OpenID provider, but set a flag to NOT ask the provider for registration info (since the user is not signing up for a new account).
- 如果用户没有登录,他们将尝试以现有用户的身份登录,因此准备重定向到他们的OpenID提供程序,但是设置一个标记,不向提供程序请求注册信息(因为用户没有注册新帐户)。
- If the user is already signed in, and this OpenID already belongs to them (i.e. the OpenID URL is mapped to the same user_id as the currently signed-in user), then you don't have to do anything (this user is already signed in and already attached that OpenID, so this is a no-op). This is an edge case.
- 如果用户已经登录,这OpenID已经属于他们(比如OpenID URL映射到相同的user_id当前登录用户),那么你不需要做任何事(这个用户已经签署了在OpenID和已连接,这是一个空操作)。这是一个边缘情况。
- If the user is already signed in but the OpenID belongs to a different user, show an error message saying that this OpenID has already been claimed by another user. You can also provide the user the option to sign out and try again. This is an edge case.
- 如果用户已经签入,但OpenID属于不同的用户,则显示一条错误消息,说明该OpenID已被另一个用户声明。您还可以向用户提供退出和重试的选项。这是一个边缘情况。
- If the OpenID is NOT currently in your database, the user is trying to sign up for a new account, so prepare to redirect to their OpenID provider and ask for registration info.
- 如果OpenID目前不在您的数据库中,那么用户正在尝试注册一个新帐户,所以准备重定向到他们的OpenID提供程序并询问注册信息。
- Save the provided openid_url in your session, since you'll need it to remember it when the OpenID provider redirects back to you, and the provider may not return it to you. If you don't have a session, you can use your database, but it has to be somewhere persistent and protected from user-tampering (i.e. not in a cookie or something that could be changed or forged by the user).
(The reason you need to store the requested OpenID is that OpenID lets users delegate their OpenID to another provider behind-the-scenes. For instance, if I try to sign up with the OpenID josephsmarr.com, I may have actually delegated that URL to a different OpenID like jsmarr.myopenid.com, and when the provider returns to you to complete authentication, you need to remember that I wanted to sign up as josephsmarr.com and not jsmarr.myopenid.com. Luckily your OpenID library will most likely handle this for you, but you still have to keep the originally requested OpenID in your session for now. This may be solved in the upcoming OpenID 2.0 spec.) - 将提供的openid_url保存在会话中,因为当OpenID提供程序重定向给您时,您需要它记住它,而提供程序可能不会将它返回给您。如果你没有会话,你可以使用你的数据库,但是它必须是一个持久的并且保护不受用户篡改的地方(例如,不在一个cookie或者其他可以被用户修改或伪造的东西中)。(需要存储所请求的OpenID的原因是,OpenID允许用户将其OpenID委托给另一个提供者。例如,如果我尝试注册OpenID josephsmarr.com,我可能已经将该URL委托给了另一个OpenID,比如jsmarr.myopenid.com,当提供者返回给您完成身份验证时,您需要记住我想注册为josephsmarr.com而不是jsmarr.myopenid.com。幸运的是,您的OpenID库很可能会为您处理这个问题,但是您仍然需要将最初请求的OpenID保存在会话中。这可以在即将发布的OpenID 2.0规范中解决)。
- Construct your return_to URL for the OpenID provider to return to after the user has authenticated. This will be your OpenID login CGI with the complete action specified.
- 构造return_to URL,以便OpenID提供程序在用户验证后返回。这将是您的OpenID登录CGI,并指定完整的操作。
- If you've determined above that the user is registering for a new account, decide what registration info to ask for. Most OpenID providers support the simple-registration extension, which is a list of common registration fields that you can request as required or optional for your site, including full name, e-mail, nickname, gender, date of birth, gender, postal code, country, language, and time zone. If you ask for these fields and the user consents to provide them, you can pre-fill them into your registration flow, thus removing time and friction from your registration process. If your OpenID consumer library doesn't natively support requesting simple-registration parameters, see if they have a general facility for supporting extensions, or worst-case you can manually add it to the generated redirect URL before redirecting.
- 如果您在上面确定用户正在注册一个新帐户,请决定需要什么注册信息。大多数OpenID提供程序都支持简单注册扩展,这是一个公共注册字段列表,您可以根据需要或可选地对您的站点进行请求,包括全名、电子邮件、昵称、性别、出生日期、性别、邮政编码、国家、语言和时区。如果您请求这些字段,并且用户同意提供这些字段,您可以将它们预填充到注册流中,从而消除注册过程中的时间和摩擦。如果您的OpenID使用者库本身不支持请求简单注册参数,请查看它们是否具有支持扩展的通用功能,或者最坏的情况是,您可以在重定向之前将其手动添加到生成的重定向URL。
- Call checkid_setup in your OpenID library to generate the URL to redirect to the user's OpenID provider. Pass in the (canonicalized) OpenID provided by the user and the return_to URL you constructed above. Also pass in the simple registration info you want if appropriate. Depending on your library, you may need to trap and handle some errors from this function. But assuming everything goes well, it will give you back a URL to redirect to.
- 调用OpenID库中的checkid_setup来生成URL以重定向到用户的OpenID提供程序。传递用户提供的(规范化的)OpenID和上面构造的return_to URL。如果合适的话,也要传递你想要的简单注册信息。根据您的库,您可能需要捕获并处理这个函数中的一些错误。但如果一切顺利,它将返回一个URL以重定向到。
- Have your CGI redirect to the provided URL, ideally by issuing a server-side redirect response.
- 让您的CGI重定向到所提供的URL,最好是通过发出服务器端重定向响应。
- The user will be redirected to their OpenID provider's web site. They will be asked to sign in (unless they've recently signed in there), they will be asked whether they trust your web site, and if you've asked for simple registration info, they'll be asked what info they want to share with you. Once they complete this process, the OpenID provider will redirect the user back to the return_to URL you supplied, which will then let you initiate your complete action to finish the job.
Here are some screenshots of signing into an OpenID provider (myopenid.com in this case) and being prompted to share some registration info with Plaxo:
- 用户将被重定向到他们的OpenID提供者的网站。他们会被要求签到(除非他们最近在那里签到),他们会被问他们是否信任你的网站,如果你问他们简单的注册信息,他们会被问他们想和你分享什么信息。一旦他们完成了这个过程,OpenID提供程序就会将用户重定向回您提供的return_to URL,然后您就可以启动完整的操作来完成任务。下面是一些登录到OpenID提供商(这里是myopenid.com)并被提示与Plaxo分享一些注册信息的截图:
- When the OpenID provider redirects to your return_to URL, they will add a bunch of additional query string parameters that contain the information needed to verify the user's authentication with this OpenID. Depending on the OpenID library you're using, you may need to gather these up into a data structure to pass in to the verification function, or it may do it for you.
- 当OpenID提供程序重定向到return_to URL时,它们将添加一些附加的查询字符串参数,这些参数包含使用这个OpenID验证用户身份所需的信息。根据您正在使用的OpenID库,您可能需要将它们收集到一个数据结构中,以便传递给验证函数,或者它可以为您这样做。
- Get the OpenID the user initially requested from your session (you stored it before redirecting to the OpenID provider above).
- 获取用户最初从会话中请求的OpenID(您在重定向到上面的OpenID提供程序之前存储了它)。
- Call id_res in your OpenID library to verify the authentication data you've been sent by the OpenID provider. Pass in the OpenID that the user initially requested, along with the query parameters as needed. This function will check to see if everything looks valid. If you get an error back, display an appropriate error message to your user. Otherwise you've now confirmed that the user has authenticated the OpenID they provided to you.
- 在OpenID库中调用id_res,以验证OpenID提供者发送的身份验证数据。输入用户最初请求的OpenID,以及需要的查询参数。这个函数将检查是否一切都是有效的。如果返回错误,请向用户显示适当的错误消息。否则,您现在已经确认用户已经验证了他们提供给您的OpenID。
- Optional: after successfully verifying the OpenID, you may wish to set a persistent cookie for your site with the OpenID used so that you can recognize that the user has an OpenID next time they come to your site and pre-fill the OpenID box on the signin page. If you do this, make sure to also clear the cookie when the user explicitly signs out.
- 可选:在成功验证OpenID之后,您可能希望使用OpenID为您的站点设置一个持久cookie,以便在用户下次访问您的站点并在登录页面上预填充OpenID框时,您可以识别用户有一个OpenID。如果这样做,请确保在用户显式退出时也清除cookie。
- Look up the verified OpenID again using the GetUserId function. If you don't find it in your database, check to see if the user is currently signed in on your site. If they are, perform the attach action below to attach this OpenID to their existing account. Otherwise, it's time to start the registration process for a new account using this OpenID. Start by storing the verified OpenID in your session so your account creation code will remember the user has already verified this OpenID. (Do NOT use the same session variable you used to store the requested OpenID, since the user can type in anything there.)
Then redirect your user to your registration flow and pass along the simple registration data you got back (if any). You will probably have to map the fields returned by simple-registration to the registration parameters that your site normally takes.- As described above, the registration page should show the OpenID prominently in the account information, and you should NOT ask the user to enter a password for your site, since they'll be using their OpenID to sign in. In addition, you should pre-fill any registration info provided from their OpenID provider. It is fine to ask for additional registration info and maintain your current policies about which fields are required and optional. (Using OpenID should be an acceleration for registering on your site, but should not require you to change what information you require or otherwise change your site's normal behavior). Finally, you should provide a link for existing users of your service to attach this OpenID to their existing account, if they have one. This will handle the case of existing users that weren't signed in and entered their OpenID and have no found themselves in the new-user registration flow. [Since this isn't common, it's better to just have a small link at the beginning of the registration flow rather than asking every user "do you want to register a new account or sign in to an existing account" when they first verify their OpenID.]
- 如上所述,注册页面应该在帐户信息的显著位置显示OpenID,并且您不应该要求用户为您的站点输入密码,因为他们将使用他们的OpenID登录。此外,您应该预先填写从他们的OpenID提供程序提供的任何注册信息。可以询问额外的注册信息并维护您当前的策略,了解哪些字段是必需的和可选的。(使用OpenID应该是站点注册的加速,但不应该要求您更改您需要的信息或更改站点的正常行为)。最后,您应该为服务的现有用户提供一个链接,以便将这个OpenID附加到他们现有的帐户(如果他们有的话)。这将处理未登录并输入OpenID且在新用户注册流中没有找到自己的现有用户的情况。[因为这并不常见,所以最好在注册流开始时使用一个小链接,而不是在用户第一次验证OpenID时问每个用户“您想注册一个新帐户还是登录到现有帐户”。]
- When the user completes your site's registration flow and you create a user account, attach the verified OpenID to the newly created account using your AttachOpenID function. [If your user table and OpenID table are in separate databases and cannot be part of the same transaction, there is a small chance that the attach command could fail and leave you with an orphaned user account. There's no easy way to prevent this in 100% of cases, but since it's rare and the user can always sign up again, in most cases you can ignore this race condition and just hope for the best.
- 当用户完成您的站点注册流程并创建用户帐户时,使用您的AttachOpenID函数将验证的OpenID附加到新创建的帐户。[如果您的用户表和OpenID表位于独立的数据库中,并且不能属于同一事务,那么attach命令可能会失败,并留给您一个孤立的用户帐户。在100%的情况下,没有简单的方法可以防止这种情况发生,但是由于这种情况很少见,而且用户总是可以再次注册,所以在大多数情况下,您可以忽略这种竞争状况,只希望得到最好的结果。
- 使用GetUserId函数再次查找已验证的OpenID。如果在数据库中找不到,请检查用户是否正在您的站点上签名。如果是,执行下面的attach操作,将这个OpenID附加到现有帐户。否则,就该使用这个OpenID启动新帐户的注册过程了。首先在会话中存储已验证的OpenID,这样您的帐户创建代码就会记住用户已经验证了这个OpenID。(不要使用您用来存储所请求的OpenID的相同会话变量,因为用户可以在其中输入任何内容。)然后将用户重定向到注册流,并传递返回的简单注册数据(如果有的话)。您可能需要将简单注册返回的字段映射到站点通常需要的注册参数。如上所述,注册页面应该在帐户信息的显著位置显示OpenID,并且您不应该要求用户为您的站点输入密码,因为他们将使用他们的OpenID登录。此外,您应该预先填写从他们的OpenID提供程序提供的任何注册信息。可以询问额外的注册信息并维护您当前的策略,了解哪些字段是必需的和可选的。(使用OpenID应该是站点注册的加速,但不应该要求您更改您需要的信息或更改站点的正常行为)。最后,您应该为服务的现有用户提供一个链接,以便将这个OpenID附加到他们现有的帐户(如果他们有的话)。这将处理未登录并输入OpenID且在新用户注册流中没有找到自己的现有用户的情况。因为这并不常见,所以最好在注册流开始时使用一个小链接,而不是在用户第一次验证OpenID时问每个用户“您想注册一个新帐户还是登录到现有帐户”。当用户完成站点注册流程并创建用户帐户时,使用AttachOpenID函数将已验证的OpenID附加到新创建的帐户。[如果您的用户表和OpenID表位于独立的数据库中,并且不能属于同一事务,那么attach命令可能会失败,并留给您一个孤立的用户帐户。在100%的情况下,没有简单的方法可以防止这种情况发生,但是由于这种情况很少见,而且用户总是可以再次注册,所以在大多数情况下,您可以忽略这种竞争状况,只希望得到最好的结果。
- If you found that the verified OpenID was attached to an existing account, you can now sign the user in as you normally would if they'd signed in through your traditional method. (If the user happens to be signed in to a different account, sign them out and then sign them in as the user the OpenID is attached to, since they just proved they own it).
- 如果您发现已验证的OpenID附加到一个现有的帐户,您现在可以像往常一样在用户通过传统方法登录时进行签名。(如果用户碰巧登录到另一个帐户,那么将其签名,然后作为OpenID的附加用户签名,因为他们刚刚证明自己拥有该帐户)。
Here's a screenshot of Plaxo's attach confirmation page:
- Require the user to be signed in (redirect through your signin page first if needed).
- 要求用户登录(如果需要的话,请先重定向登录您的登录页面)。
- Fetch the list of attached OpenIDs for the signed-in user by calling your GetOpenIDsByUser function.
- 通过调用GetOpenIDsByUser函数来获取已注册用户的附加openid列表。
- Show the list of OpenIDs in a web page with a link by each one to detach it if the user wants. The links will call the delete action below and pass in the OpenID to delete as the openid_url parameter.
- 在web页面中显示openid列表,每个页面都有一个链接,以便在用户需要时将其分离。链接将调用下面的delete操作,并将OpenID作为openid_url参数传递给delete。
- Provide a link or input box to attach an additional OpenID. This will take the user through the login and attach flows (since the user is already signed in) and end up back on the list page.
- 提供附加的OpenID的链接或输入框。这将使用户通过登录和附加流(因为用户已经登录)并返回到列表页面。
- If your site already has a general settings page, you should provide a link to "Manage your OpenIDs" that links to this list page. You may also decide to build this functionality directly into your current settings page.
Here's a screenshot of Plaxo's list page, as well as links to it from our current settings pages:
- 如果你的站点已经有一个通用设置页面,你应该提供一个链接来“管理你的openid”,链接到这个列表页面。您还可以决定将此功能直接构建到当前设置页面中。这里是Plaxo的列表页面的截图,以及我们当前设置页面的链接:
- Require the user to be signed in (redirect through your signin page first if needed).
- 要求用户登录(如果需要的话,请先重定向登录您的登录页面)。
- Optional: Check whether the user is trying to delete the last credential they could use to sign in to your site. If the user has not set up a normal password on your site and this is the only OpenID attached to their account, deleting their last OpenID would essentially lock them out of their account forever. If you don't have a good way to recover users in this situation, show an error message if the user tries to delete their last attached credential, saying essentially "You can't delete the last OpenID attached to your account because you'd have no way to sign in. First attach another OpenID or create a password for this site."
- 可选:检查用户是否试图删除他们可以用来登录到您的站点的最后凭据。如果用户没有在您的站点上设置一个普通的密码,并且这是唯一一个附加到他们的帐户上的OpenID,删除他们的最后一个OpenID将基本上永远锁在他们的帐户之外。如果您在这种情况下没有很好的方法来恢复用户,如果用户试图删除他们最后的附加凭证,显示一条错误消息,本质上说“您不能删除附加到您的帐户上的最后一个OpenID,因为您没有办法登录。”首先附加一个OpenID或为这个站点创建一个密码。
- Assuming it's ok to proceed, detach the OpenID provided by the openid_url parameter from the signed-in user's account by calling your DetachOpenID function. If the OpenID provided is not currently attached to the user's account, you can choose to show an error or just treat it as a no-op success.
- 假设可以继续,那么通过调用DetachOpenID函数将openid_url参数提供的OpenID从注册用户的帐户中分离出来。如果提供的OpenID目前没有附加到用户的帐户上,您可以选择显示错误或将其视为无操作成功。
- Show a confirmation message that this OpenID has now been detached and can no longer be used to sign in to your site. Tell the user that if they want to re-attach this OpenID, they will have to go through the normal verification process to re-attach it. Consider redirecting to the list action so the user can see the updated list of OpenIDs attached to their account.
Here are some screenshots of detaching an OpenID from a Plaxo account:
- 显示一个确认消息,这个OpenID现在已经被分离,不能再用于登录您的站点。告诉用户,如果他们想重新连接这个OpenID,他们必须通过正常的验证过程才能重新连接它。考虑重定向到list操作,以便用户可以看到附加到其帐户的更新的openid列表。下面是一些从Plaxo账户中分离OpenID的截图:
- If your site currently lets users delete their accounts, it's important that you also detach any OpenIDs that were attached so they can be re-attached to another account later. You can do this by calling your DetachOpenIDsByUser function inside your delete-user routine, or by otherwise triggering this function when deleting a user.
- 如果您的站点目前允许用户删除他们的帐户,那么重要的是您也要分离任何附加的openid,以便以后可以将它们重新附加到另一个帐户。您可以通过在删除用户例程中调用DetachOpenIDsByUser函数来实现这一点,或者在删除用户时触发此函数。
...and you're done!
Snipped.. so check the wayback machine link up above for the rest. Joseph goes through some best practices for OpenID, but at this point you should have a working example.
剪掉. .因此,请检查上面的wayback机器连接到上面的其他部分。Joseph介绍了OpenID的一些最佳实践,但是现在您应该有一个可用的示例。