我真的是Web开发的新手,我正在尝试使用NodeJS Express和EJS与google oAuth制作一个小型应用程序。问题是我对中间件之间如何相互连接以及如何真正了解不多,所以我有:
在this Google tutorial中进行配置的app.js和auth.js以及呈现在我应用程序每个页面中的EJS标头,看起来像这样:
<% if (locals.profile) { %>
<span style="display:inline-block; width:150px;">
<a href="#" class="badge badge-primary"> <%= profile.displayName %> </a>
</span>
<a class="btn btn-sm btn-outline-secondary" href= <%=logout%> >Log Out</a>
<% } else { %>
<a class="btn btn-sm btn-outline-secondary" href="/auth/login">Log In</a>
<% } %>
问题是,当我从/auth/login
通过/index
登录时,我不愿返回\index
,但标题仍然空白并为我提供登录信息>
但是,如果我在我的auth.js末尾添加router.get('/leaderboard', authRequired);
,则标题将按预期工作(请向我显示我的登录名并显示“注销”按钮,而不是“登录”),但仅在这条路线上(例如/leaderboard
)
我尝试了router.get('/', authRequired);
,但工作正常,但是它要求用户登录才能访问索引,这不好,我希望用户自由浏览大部分页面(考虑到它是博客类型的应用程序:您可以查看其他博客,但在您未登录时无法访问“编辑我的个人资料”或“新帖子”页面)
我还尝试设置本地人,并从extractProfile
和其他地方手动调用addTemplateVariables
和get('/auth/login')
(我承认,这是盲目的),但这根本没有用。
我感到被困住了,就像我在理解表达本身的工作原理时缺少重要的东西。有人可以指出我的意思吗?
感谢您的帮助!
PS 1:我正在localhost上进行测试
PS 2:这是我的auth.js:
// Copyright 2017, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
'use strict';
const express = require('express');
const config = require('./config');
// [START setup]
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
function extractProfile(profile) {
let imageUrl = '';
if (profile.photos && profile.photos.length) {
imageUrl = profile.photos[0].value;
}
let email = '';
if (profile.emails && profile.emails.length) {
email = profile.emails[0].value;
}
return {
id: profile.id,
displayName: profile.displayName,
image: imageUrl,
email: email,
name: profile.name,
};
}
// Configure the Google strategy for use by Passport.js.
//
// OAuth 2-based strategies require a `verify` function which receives the
// credential (`accessToken`) for accessing the Google API on the user's behalf,
// along with the user's profile. The function must invoke `cb` with a user
// object, which will be set at `req.user` in route handlers after
// authentication.
passport.use(
new GoogleStrategy(
{
clientID: config.get('OAUTH2_CLIENT_ID'),
clientSecret: config.get('OAUTH2_CLIENT_SECRET'),
callbackURL: config.get('OAUTH2_CALLBACK'),
accessType: 'offline',
userProfileURL: 'https://www.googleapis.com/oauth2/v3/userinfo',
},
(accessToken, refreshToken, profile, cb) => {
// Extract the minimal profile information we need from the profile object
// provided by Google
cb(null, extractProfile(profile));
}
)
);
passport.serializeUser((user, cb) => {
cb(null, user);
});
passport.deserializeUser((obj, cb) => {
cb(null, obj);
});
// [END setup]
const router = express.Router();
// [START middleware]
// Middleware that requires the user to be logged in. If the user is not logged
// in, it will redirect the user to authorize the application and then return
// them to the original URL they requested.
function authRequired(req, res, next) {
if (!req.user) {
req.session.oauth2return = req.originalUrl;
return res.redirect('/auth/login');
} else {
res.locals.profile = req.user;
res.locals.login = `/auth/login?return=${encodeURIComponent(
req.originalUrl
)}`;
res.locals.logout = `/auth/logout?return=${encodeURIComponent(
req.originalUrl
)}`;
}
next();
}
// Middleware that exposes the user's profile as well as login/logout URLs to
// any templates. These are available as `profile`, `login`, and `logout`.
function addTemplateVariables(req, res, next) {
res.locals.profile = req.user;
res.locals.login = `/auth/login?return=${encodeURIComponent(
req.originalUrl
)}`;
res.locals.logout = `/auth/logout?return=${encodeURIComponent(
req.originalUrl
)}`;
next();
}
// [END middleware]
// Begins the authorization flow. The user will be redirected to Google where
// they can authorize the application to have access to their basic profile
// information. Upon approval the user is redirected to `/auth/google/callback`.
// If the `return` query parameter is specified when sending a user to this URL
// then they will be redirected to that URL when the flow is finished.
// [START authorize]
router.get(
// Login url
'/auth/login',
// Save the url of the user's current page so the app can redirect back to
// it after authorization
(req, res, next) => {
if (req.query.return) {
req.session.oauth2return = req.query.return;
}
next();
},
// Start OAuth 2 flow using Passport.js
passport.authenticate('google', {scope: ['email', 'profile']})
);
// [END authorize]
// [START callback]
router.get(
// OAuth 2 callback url. Use this url to configure your OAuth client in the
// Google Developers console
'/auth/google/callback',
// Finish OAuth 2 flow using Passport.js
passport.authenticate('google'),
// Redirect back to the original page, if any
(req, res) => {
const redirect = req.session.oauth2return || '/';
delete req.session.oauth2return;
res.redirect(redirect);
}
);
// [END callback]
// Deletes the user's credentials and profile from the session.
// This does not revoke any active tokens.
router.get('/auth/logout', (req, res) => {
req.logout();
res.redirect('/');
});
router.get('/leaderboard', authRequired);
module.exports = {
extractProfile: extractProfile,
router: router,
required: authRequired,
template: addTemplateVariables,
};