我正在尝试创建一个无密码身份验证的应用程序,以及Facebook和邮件等社交媒体。
我愚蠢地坚持了一点,也许我不明白。
让我的项目命名为MyApp:
如果用户尝试从myapp.com/
登录Facebook,则会将其重定向到facebook.com/login
,然后Facebook将其重定向到myapp.com/callback
。
因此,在我的服务器上,路由/
和/callback
完全相同:它们只是将我的React应用程序发送给用户,但/callback
生成JWT令牌。
从这里开始我的问题是:如何在React应用程序的同时将JWT令牌发送到客户端?
也许我错过了其他提供商的东西,但邮件的无密码原则是一回事:只是一个验证用户的链接,只是重定向到/callback
,没有外部提供商。
我完全迷失了:(
谢谢!
答案 0 :(得分:3)
您可以将JWT放入要将用户重定向到的URL的查询字符串中。然后,您从客户端获取JWT以访问查询字符串,并将其保存到本地存储。我最近自己完成了检查我的回购server here,client here
编辑:我在服务器中发布回调路由的代码,并在客户端获取令牌以获取更多详细信息,检查上面的回购链接
回拨路线
app.get('/auth/github/callback', (req,res) => {
githubAuth.code.getToken(req.originalUrl)
.then(user => {
console.log(user.data);
return fetch('https://api.github.com/user?access_token=' + user.accessToken);
})
.then(result => {
return result.json();
})
.then(json => {
//console.log(json);
//res.send(json);
return User.findOne({githubId: json.id})
.then(currentUser => {
if(currentUser){ // user already exists
console.log('User exists with GitHub Login: ' + currentUser);
return currentUser;
}
else{ // User doesn't exist
// saved automatically using mongoose, returns Promise
return new User({
username: json.login,
githubId: json.id
}).save()
.then(newUser => {
console.log('New User created with GitHub Login: ' + newUser);
return newUser;
});
}
});
})
.then(user => {
// Now use user data to create a jwt
const token = jwt.sign({id: user._id}, process.env.JWT_ENCRYPTION_KEY, {
expiresIn: 86400 // expires in 24 hours
});
const encodedToken = encodeURIComponent(token);
res.status(200);
res.redirect('/profile?token=' + encodedToken);
})
.catch(err => console.log(err));
});
客户端中的令牌检索
class UserProfile extends React.Component{
constructor(props){
super(props);
this.state = {username: ''};
}
componentDidMount(){
const query = new URLSearchParams(this.props.location.search)
// When the URL is /the-path?some-key=a-value ...
let token = query.get('token')
console.log(token)
if(token){ // it's the first time we receive the token
// we save it
console.log('Saving token');
localStorage.setItem('userjwt', token);
}
else{
// if qrstring is empty we load the token from storage
token = localStorage.userjwt;
console.log('Loading token: ' + token);
}
if(token){
const headers = new Headers({
'x-access-token': token
});
const reqOptions = {
method: 'GET',
headers: headers
};
fetch('/user', reqOptions)
.then(res => res.json())
.then(user => {
console.log(user);
console.log(user.username);
this.setState({username: user.username});
})
}
}
render(){
if(this.state.username === ''){
return(
<div className="social-profile">
<h2>Login first</h2>
</div>
);
}
else{
return(
<div className="social-profile">
<h2>User: {this.state.username}</h2>
</div>
);
}
}
}
答案 1 :(得分:2)
这就是我在应用程序中的操作方式,请注意,由于Thomas提到的与安全here相关联的安全问题(,并且需要Redis (或数据库(如果您愿意)。
我所做的不是代替直接在查询参数上传递JWT,而是:
localStorage
redisClient.set(randomToken, jwtToken, "EX", 60);
res.redirect(`http://example.com/jwt?token=${randomToken}`);
这需要更多的工作,资源和一个额外的HTTP请求来获取JWT,但是考虑到直接在查询参数中传递JWT的风险,我认为这是值得的。并不是说用户会每分钟都进行身份验证。