如何提供带身份验证的静态文件?

How do I serve static files with authentication?

这是我的文件夹结构:

/app
  server.js

  /public
    index.html
    script-a.js

    /scripts
      script-b.js

这些是我index.html的相关内容:

<!-- index.html -->
.....
...
<script scr="/script-a.js"></script>
<script scr="/script-b.js"></script>

这些是server.js的相关内容:

import express                          from 'express'
import session                          from 'express-session'
import NedbStore                        from 'nedb'
import passport                         from 'passport'
import { Strategy as FacebookStrategy } from 'passport-facebook'
import { ensureLoggedIn }               from 'connect-ensure-login'
....
..
const db  = new NedbStore({ filename: `${__dirname}/db/nedb.db`, autoload: true })
const DB  = dbAsyncWrapper(db)

app.use(cors({
   origin: '*',
   credentials: true,
   optionSuccessStatus: 200
}))

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:4200')
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
  res.header('Access-Control-Allow-Methods', 'POST, GET')
  next()
})

app.use(cookieParser())
app.use(express.json({ limit: '50mb' }))
app.use(express.urlencoded({ extended: true, limit: '50mb' }))

app.use(session({
  secret: 'googoogaga',
  resave: false,
  saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())

passport.use(new FacebookStrategy({
  clientID      : FACEBOOK_APP_ID,
  clientSecret  : FACEBOOK_APP_SECRET,
  callbackURL   : "http://localhost:4200/facebook/callback",
  profileFields : ['id']
}, async(accessToken, refreshToken, profile, done) => {
  let facebookId = profile.id
  let userInDb =  await DB.getUser()
  if (userInDb && userInDb.facebookId === facebookId) {
    await DB.updateUser({ accessToken })
    done(null, userInDb)
  } else {
    let newUser = await DB.updateUser({ facebookId, accessToken })
    done(null, newUser)
  }
}))

passport.serializeUser(function(user, done) {
  done(null, user)
})

passport.deserializeUser(function(user, done) {
  done(null, user)
})

app.use('/', ensureLoggedIn('/auth/facebook'), express.static(__dirname + '/public'))

app.get('/auth/facebook', passport.authenticate('facebook', { scope:'email' }))

app.get('/facebook/callback', passport.authenticate('facebook', {
  successRedirect : '/',
  failureRedirect : '/auth/facebook'
}))

使用上面的代码,我期望:

  1. 转到/
  2. 被重定向到 facebook 进行登录
  3. 返回/
  4. 已经 index.html 服务和加载
  5. 正确加载 script-a.jsscript-b.js

实际情况是:

我转到 /,我被重定向到 /auth/facebook,状态代码为 302

如果我删除:

app.use('/', ensureLoggedIn('/auth/facebook'), express.static(__dirname + '/public'))

改为手动声明每个路由处理程序,一切正常:

....
..
app.get('/', ensureLoggedIn('/auth/facebook'), (req,res) => {
  res.sendFile(__dirname + '/public/index.html')
})
app.get('/script-a.js', ensureLoggedIn('/auth/facebook'), (req,res) => {
  res.sendFile(__dirname + '/public/script-a.js')
})
app.get('/script-b.js', ensureLoggedIn('/auth/facebook'), (req,res) => {
  res.sendFile(__dirname + '/public/scripts/script-b.js')
})

如果你的授权是这样实现的:

app.use('/public', ensureLoggedIn('/auth/facebook'));

然后,您可以 运行 在您的 express.static() 路线之前:

app.use(ensureLoggedIn('/auth/facebook'));
app.use(express.static(__dirname + '/public'));

或者,您将其专门合并到静态路由中:

app.use(ensureLoggedIn('/auth/facebook'), express.static(__dirname + '/public'));

When I also include the first 2 lines, not even the index.html gets served. I only get a failed facebook redirect registered on the network panel.

然后,您的身份验证中间件要么正确地拒绝对未经授权的客户端的访问,要么您的身份验证中间件无法正常工作。您的问题中没有任何内容表明可能是或可以让我们为您诊断。

But all other static files fail to be served.

为了帮助您解决这个问题,我们必须查看未正确提供的静态文件的具体信息(URL 在网页中,资源在您的文件系统中的位置, ETC...)。为了使静态文件正常工作,人们会犯 4-5 个常见错误。最常见的只是在网页中使用错误的 URL 静态资源,例如图像,CSS 文件,脚本文件等...

不幸的是,我找到的唯一解决方案是将我的 /public 文件夹变成平面结构并执行:

app.get('/', ensureLoggedIn('/auth/facebook'), (req,res) => {
  res.sendFile(__dirname + '/public/index.html')
})

app.get('/:filename', ensureLoggedIn('/auth/facebook'), (req,res) => {
  res.sendFile(__dirname + `/public/${req.params.filename}`)
})