我正在使用Auth0托管我的所有用户数据。我也有自己的后端,我希望有一个Users
表,它将我的数据库生成的userId
映射到Auth0的user_id
。我在注册的两个流程之间犹豫不决:
user_id
。POST /users
(公共端点)上调用后端以使用user_id
创建一个新用户。user_id
,因此数据库在user_id
和我的userId
之间进行了查找。POST /users
。该调用将生成我的数据库的userId
并将其发送回Auth0。userId
放入Auth0的user_metadata
。user_metadata
将包含在JWT中,因此对后端进行的所有获取资源的调用都将包含数据库的userId
(无需额外查找)。我觉得2更扎实。还有其他注册流程吗?某些auth0客户是否使用与我的#2类似的流程?我没有在他们的文档中找到很多东西。
答案 0 :(得分:5)
这是我的第一篇文章,所以如果我犯任何新手错误,请原谅。
我发现注册流程1运作良好。您没有指定要使用的技术,但这里是我的github的链接,在这里我有一个功能完整的博客,使用带有React,redux和Express后端的Sign-up flow 1。
https://github.com/iqbal125/react-redux-fullstack-blog
我将通过这些框架进行演示,因此希望您可以针对所使用的框架调整代码。
我的注册过程如下:
1。前端显示“锁定”用户注册了
login() {
this.auth0.authorize();
}
2。用户被重定向到回调页面。
我的回调页面非常简单,我将其用作功能组件。
<div>
<h2>Callback</h2>
</div>
3。然后,我从回调页面重定向到“身份验证”页面
我通过auth.js util组件中的handleAuthentication()函数完成此操作。该代码从auth0示例中进行了略微修改。
handleAuthentication() {
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.setSession(authResult);
this.getProfile();
setTimeout( function() { history.replace('/authcheck') }, 2000);
} else if (err) {
history.replace('/');
console.log(err);
alert(`Error: ${err.error}. Check the console for further details.`);
}
});
}
您会注意到我添加了getProfile()函数
getProfile() {
let accessToken = this.getAccessToken();
if(accessToken) {
this.auth0.client.userInfo(accessToken, (err, profile) => {
if (profile) {
this.userProfile = { profile };
}
});
}
}
以及getAccessToken()函数
getAccessToken() {
if (localStorage.getItem('access_token')) {
const accessToken = localStorage.getItem('access_token')
return accessToken
}
else {
console.log("No accessToken")
return null
}
}
auth.js util组件中的这两个函数将使我们能够从auth0获取信息并将其保存到在类中声明的空对象中。
userProfile = {}
继续进行auth-check.js容器。我首先在构造函数中声明函数,然后是函数本身。然后,我调用componentDidMount()生命周期方法,该方法在组件呈现时自动运行。
constructor() {
super()
this.send_profile_to_db = this.send_profile_to_db.bind(this)
}
send_profile_to_db (profile) {
const data = profile
axios.post('api/post/userprofiletodb', data)
.then(() => axios.get('api/get/userprofilefromdb', {params: {email: profile.profile.email}} )
.then(res => this.props.db_profile_success(res.data))
.then(history.replace('/')))
}
我的生命周期方法和Im返回一个空div。
componentDidMount() {
if(this.props.auth.isAuthenticated()) {
this.props.login_success()
this.props.db_profile_success(this.props.auth.userProfile)
this.send_profile_to_db(this.props.auth.userProfile)
} else {
this.props.login_failure()
this.props.profile_failure()
this.props.db_profile_failure()
history.replace('/')
}
}
render() {
return (
<div>
</div>
)
}
}
我认为这里的代码成为您提出问题的核心。
我将从 send_profile_to_db()函数开始。
这里我使用axios发出请求。我开始对Express服务器进行后端api调用(我将在下一步中进行说明),然后Im将用户配置文件作为数据对象参数传递给axios。您可能想知道实际的用户配置文件数据来自何处。
在我的route.js根组件中,我导入并初始化了Auth的新实例
export const auth = new Auth();
然后将其作为道具传递给AuthCheck组件。
<Route path="/authcheck" render={(props) => <AuthCheck auth={auth} {...props} />} />
这使我可以使用“ this.props”访问auth类的所有属性。因此,我仅使用我们在最后一步中初始化的“ userProfile = {}”对象,该对象现在包含我们的用户数据。
在使用嵌套的“ .then()”函数将数据发布到数据库Im之后,该函数调用axios get请求并将用户电子邮件作为参数,用于从数据库中查找配置文件。数据库概要文件包含有关用户帖子和用户评论的数据。这对于在应用程序中显示数据很有用。然后,Im使用另一个“ .then()”语句和Redux Thunk将用户配置文件数据异步保存到全局Redux状态。
因此,总而言之,此authcheck组件正在执行4件事:
1.将我们从auth0获得的用户配置文件数据保存到我们自己的数据库中。
2.然后,在保存数据后,立即从我们的数据库中检索相同的配置文件。
3.让我们的应用知道用户是否通过身份验证。
4.将我们的数据库用户配置文件数据保存为全局redux状态,以供其他组件使用。
如果您问我,真棒!
4。 api调用检查用户是否已经在sql db中,然后保存用户数据,否则不执行任何操作。
现在这是我的服务器设置。为用户提供数据库“发布”和“获取”请求。
router.post('/api/post/userprofiletodb', (req, res, next) => {
const values = [req.body.profile.nickname, req.body.profile.email, req.body.profile.email_verified]
pool.query('INSERT INTO users(username, email, date_created, email_verified) VALUES($1, $2, NOW(), $3) ON CONFLICT DO NOTHING', values, (q_err, q_res) => {
if (q_err) return next(q_err);
console.log(q_res)
res.json(q_res.rows);
});
});
/* Retrieve user profile from db */
router.get('/api/get/userprofilefromdb', (req, res, next) => {
// const email = [ "%" + req.query.email + "%"]
const email = String(req.query.email)
pool.query("SELECT * FROM users WHERE email = $1", [ email ], (q_err, q_res) => {
res.json(q_res.rows)
});
});
一些注意事项:
路由器对象是express.router()。我正在使用psql。
请记住添加“禁止冲突”,否则您将保存同一用户的多个版本。
我认为auth0还为您提供了更多数据点,但最终我没有使用它们。
这是我的users表的SQL模式。
CREATE TABLE users (
uid SERIAL PRIMARY KEY,
username VARCHAR(255) UNIQUE,
email VARCHAR(255),
email_verified BOOLEAN,
date_created DATE,
last_login DATE
);
5。然后,用户数据将保存为redux全局状态,并可用于在用户个人资料页面上显示数据。
我最后只是在步骤3中对此进行了解释。
6。当用户单击注销时,将再次调用authcheck,并且将从全局状态中删除用户信息,然后注销用户。
请参阅步骤3
7。 auth-check然后重定向回首页。
再次参见步骤3。
如果您有兴趣或想念任何东西,请务必查看我的存储库,就像我说的那样,它是一个功能全面的博客。
答案 1 :(得分:1)
流程 1 会在每次成功登录时对您的数据库执行“插入或忽略”命令,在大规模情况下,这不是一个好习惯。事实上,它也是一个潜在的 DoS 点,因为这个端点直接暴露了数据库。
因此 Flow 2 在我看来是一个更好的选择,因为它只会在您的数据库和 Auth0 的数据库之间同步一次。这里唯一的挑战是处理注册后流程中的失败。
另请注意,正如评论中所建议的,app_metadata
更适合存储此类信息。