25

我已经阅读了有关使用 Google 处理来自该网站的登录的信息,但它并没有详细解释数据库应该如何处理。

通常对于数据库中的用户帐户,您将拥有诸如id, username,password等字段。根据我在链接中阅读的内容,您最终将获得用户的 ID 令牌,并且内部是一个名为“ sub”的键,其值在您可以使用它来识别用户。

我的问题是,这个“ sub”将存储在数据库中的什么位置?会去id野外吗?Username场地?

我认为它不应该进入该领域,因为有人可能会创建一个与某人的 Google idusername完全相同的用户名。sub但把它放在id现场也似乎很奇怪。

此外,表中是否需要另一个user accounts布尔字段才能区分本地登录用户和通过 Google 登录的用户?

4

2 回答 2

46

创建一个EXTERNAL_ID 列,并使用它来存储来自外部系统的标识符。您应该添加一个EXTERNAL_TYPE 列并将其设置为“GOOGLE”。当您要集成更多身份验证提供程序时,可以将其设置为不同的值(例如“OPEN_ID”、“FACEBOOK”。)

与外部系统交互时,始终需要存储外键/标识符,以便可靠地访问和更新外部记录。

外部密钥与本地数据库中的 ID 不同,它绝对不是用户名。它只是它自己的列,并且应该具有相当大的大小,以便可以存储遇到的任何外部 ID。

VARCHAR(64) 可能是一个好的开始,因为根据定义,我们不对标识符的类型或内容负责——这些是由外部系统提供和定义的。我们只需要保持它的值不变,在与外部系统对话时使用。

EXTERNAL_TYPE 字段可让您区分“本地注册”和“通过 Google 注册”或其他外部提供商的用户。

例如:

create table "USER" (
    ID            int not null,
    USERNAME      varchar(64),
    DISPLAY_NAME  varchar(64),
    EMAIL         varchar(128),

    PWD_HASH      varchar(32),   -- "native" password, salted & hashed for security
    PWD_SALT      varchar(32),

    EXTERNAL_TYPE varchar(16),   -- external-auth Type & ID.
    EXTERNAL_ID   varchar(64),

    primary key (ID)
);

请注意,某些网站使用稍微高级一点的方案,用户既可以通过 Google 注册,也可以通过本机密码登录。在这种情况下,通过一个凭据系统登录会检测到现有的电子邮件和其他凭据系统——这通常会提示用户使用其他凭据进行身份验证、链接它们并同时使用它们。这仍然基于 EXTERNAL_ID 和 EXTERNAL_TYPE 但可以将它们放在与 USER 相关的 USER_CREDENTIALS 表上,而不是 USER 表本身。

对于用户身份验证,也可以想象您可能需要一个额外的列来存储某种加密/密钥/令牌。不确定,只是一种可能。

于 2013-09-21T02:06:43.353 回答
0

我可能对此有一个不错的答案,因为我目前正面临这个问题。

我的解决方案有以下要求

  • 用户拥有一个或多个帐户
  • 帐户可以是基于密码的帐户或任何其他基于社交登录的帐户
  • 每个帐户只能使用一次电子邮件,如果您通过 Facebook 使用 abc@example.com 注册,则表格中不能有另一行也使用 Facebook 和 abc@example.com
  • 您可以将任意数量的帐户与给定用户关联,并且
  • 用户不再有电子邮件的概念,但帐户有

在这种方案下,用户表只有 2 个字段

users (user_id, enabled)

可以使用单个标志启用或禁用整个用户及其所有帐户

authentication_types 表包含支持哪些登录方法的详细信息

authentication_types (authentication_type_id, authentication_type_name)

帐户表包含所有用户数据

accounts (account_id, email, email_verified, password, nickname, picture_url, is_primary_email, authentication_type_id, created_at, updated_at)

user_accounts 表会将正确的 user_id 与正确的 account_id 链接起来

user_accounts (user_id, account_id)

密码将为空,其中 authentication_type_id 表示社交登录 external_login_id 将为空,其中 authentication_type_id 表示密码登录

这是完整的架构

-- The below database I believe can handle multiple accounts per user with ease.
-- As a user, you can have an account with abc@example.com as email and a hashed password
-- You can also link your account via Facebook with the same email abc@example.com or
-- a different one such as xyz@example.com

CREATE TABLE IF NOT EXISTS authentication_types (
authentication_type_id INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY,
authentication_type_name VARCHAR NOT NULL,
PRIMARY KEY(authentication_type_id),
UNIQUE(authentication_type_name)
);

INSERT INTO authentication_types VALUES
(1, 'password'), 
(2, 'facebook'), 
(3, 'google'), 
(4, 'github'), 
(5, 'twitter');

-- The user has one or more accounts
-- The user can have only one account of a given type
-- Example: only 1 Facebook account and 1 Google account
-- If you feel this is restrictive let me know a better way

CREATE TABLE IF NOT EXISTS users (
user_id INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY, 
enabled BOOLEAN NOT NULL DEFAULT TRUE, 
PRIMARY KEY(user_id)
);

CREATE TABLE IF NOT EXISTS accounts (
account_id INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY, 
email VARCHAR NOT NULL, 
password VARCHAR, 
email_verified BOOLEAN NOT NULL DEFAULT FALSE, 
nickname VARCHAR, 
picture_url VARCHAR, 
is_primary_email BOOLEAN NOT NULL DEFAULT FALSE,
authentication_type_id INTEGER NOT NULL,
external_login_id VARCHAR,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY(account_id),
UNIQUE(email),
UNIQUE(authentication_type_id, email),
UNIQUE(authentication_type_id, external_login_id),
FOREIGN KEY (authentication_type_id) REFERENCES authentication_types (authentication_type_id) ON UPDATE CASCADE ON DELETE CASCADE
);

-- the users with authentication_type_id as password will actually have a password
-- If we say email is unique, it becomes problematic
-- What if you have the same email on your Facebook and Google account?
-- So instead we say that the combination of authentication_type_id and email is unique
-- external_login_id is nothing but the unique login ID assigned by Twitter, Github etc
-- There is nothing to say that they are truly unique
-- It is possible that the Facebook ID for a user may be the same as the Pinterest ID for another user
-- So instead we say that the combination of authentication_type_id and external_login_id is unique

CREATE TABLE IF NOT EXISTS user_accounts (
user_id INTEGER NOT NULL,
account_id INTEGER NOT NULL,
PRIMARY KEY(user_id, account_id),
FOREIGN KEY (user_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (account_id) REFERENCES accounts(account_id) ON UPDATE CASCADE ON DELETE CASCADE
);

-- user A with only password based account

INSERT INTO accounts(account_id, email, password, email_verified, nickname, picture_url, is_primary_email, authentication_type_id, external_login_id) VALUES (
1, 
'abc@example.com', 
'$2b$11$oHR4Tdcy8Mse1lB5Hmgj5O3u3SPgqolHRgBEVXvzLt5BjS8ujGXKS',
false,
null,
null,
true,
1,
null
);

INSERT INTO users VALUES(1, true);
INSERT INTO user_accounts VALUES(1, 1);

-- user B with password and facebook account

INSERT INTO accounts(account_id, email, password, email_verified, nickname, picture_url, is_primary_email, authentication_type_id, external_login_id) VALUES (
2, 
'bcd@example.com', 
'$2b$11$oHR4Tdcy8Mse1lB5Hmgj5O3u3SPgqolHRgBEVXvzLt5BjS8ujGXKS',
false,
null,
null,
true,
1,
null
);

INSERT INTO accounts(account_id, email, password, email_verified, nickname, picture_url, is_primary_email, authentication_type_id, external_login_id) VALUES (
3, 
'xyz@example.com', 
null,
true,
null,
null,
false,
1,
'hjdigodgjaigfshg123461'
);

INSERT INTO users VALUES(2, true);
INSERT INTO user_accounts VALUES(2, 2);
INSERT INTO user_accounts VALUES(2, 3);

SELECT * FROM accounts;
SELECT * FROM users;
SELECT * FROM user_accounts;

链接到 DBFIDDLE

任何有关如何进一步改进的建议都非常受欢迎!

于 2021-12-09T13:50:17.490 回答