@auth/express
@auth/express
现在处于实验阶段。API 将在未来发生变化。
Express Auth 是 Auth.js 的官方 Express 集成。它提供了一种简单的方法,只需几行代码即可将身份验证添加到您的 Express 应用程序。
安装
npm install @auth/express
用法
import { ExpressAuth } from "@auth/express"
import GitHub from "@auth/express/providers/github"
import express from "express"
const app = express()
// If app is served through a proxy, trust the proxy to allow HTTPS protocol to be detected
// https://express.js.cn/en/guide/behind-proxies.html
app.set('trust proxy', true)
app.use("/auth/*", ExpressAuth({ providers: [ GitHub ] }))
不要忘记设置 AUTH_SECRET
环境变量。这应该是一个至少 32 个字符的随机字符串。在 UNIX 系统上,您可以使用 openssl rand -hex 32
或查看 https://generate-secret.vercel.app/32
。
您还需要将环境变量加载到运行时环境中。例如,在 Node.js 中使用 dotenv
或 Deno 中的 Deno.env
。
提供者配置
除非您在不同的路径上安装 ExpressAuth
处理程序,否则 提供者 使用的回调 URL 必须设置为以下内容:
[origin]/auth/callback/[provider]
登录和注销
一旦您的应用程序被安装,您就可以通过从客户端代码向以下 REST API 端点 发出请求来登录或注销。注意:请确保在所有登录和注销请求的请求正文中包含 csrfToken
。
管理会话
如果您使用的是带有模板引擎的 Express(例如 EJS、Pug),您可以通过以下方式使用中间件将会话数据提供给所有路由:
import { getSession } from "@auth/express"
export function authSession(req: Request, res: Response, next: NextFunction) {
res.locals.session = await getSession(req)
next()
}
app.use(authSession)
// Now in your route
app.get("/", (req, res) => {
const { session } = res.locals
res.render("index", { user: session?.user })
})
授权
您可以通过检查会话是否存在来保护路由,如果会话不存在,则重定向到登录页面。这可以在每个路由中完成,或者使用以下中间件对一组路由进行保护:
export async function authenticatedUser(
req: Request,
res: Response,
next: NextFunction
) {
const session = res.locals.session ?? (await getSession(req, authConfig))
if (!session?.user) {
res.redirect("/login")
} else {
next()
}
}
每个路由
要保护单个路由,只需将中间件添加到路由中,如下所示:
// This route is protected
app.get("/profile", authenticatedUser, (req, res) => {
const { session } = res.locals
res.render("profile", { user: session?.user })
})
// This route is not protected
app.get("/", (req, res) => {
res.render("index")
})
app.use("/", root)
每个路由组
要保护一组路由,请定义一个路由器并将中间件添加到路由器中,如下所示:
import { Router } from "express"
const router = Router()
router.use(authenticatedUser) // All routes defined after this will be protected
router.get("/", (req, res) => {
res.render("protected")
})
export default router
然后,我们安装路由器,如下所示:
import protected from "./routes/protected.route"
app.use("/protected", protected)
有关 ESM 的说明
@auth/express 仅限 ESM。这意味着您的 package.json 必须包含 "type": "module"
,并且 tsconfig.json 应该包含 "module": "NodeNext"
或 ESNext
。文件导入必须使用 .js
扩展名,例如 import { MyRouter } from "./my-router.js"
。
您的开发服务器应该使用 tsx 运行,并使用 tsx index.ts
(快速启动,没有类型检查),或者使用 ts-node 运行,并使用 ‘node —loader ts-node/esm index.ts’(启动速度较慢,但有类型检查)。
虽然不推荐,但如果您希望在 CommonJS 项目中使用 @auth/express 而不进行迁移并进行上述更改,则可以使用 tsx 运行开发服务器,并且可能可以使用 pkgroll 进行编译。将 ‘“name”: ”./dist/index.js”’ 或 ‘“name”: ”./dist/index.mjs”’ 添加到您的 package.json 中,然后运行 ‘pkgroll’ 以使用 ESM 和 CommonJS 支持进行编译。对于新项目,建议直接使用 ESM。
AuthError
所有 Auth.js 错误的基类错误。它经过优化,可以通过 logger.error
选项以格式良好的方式在服务器日志中打印。
扩展
构造函数
new AuthError(message, errorOptions)
new AuthError(message?, errorOptions?): AuthError
参数
参数 | 类型 |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
返回值
覆盖
Error.constructor
属性
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
类型声明
错误?
optional err: Error;
覆盖
Error.cause
消息
message: string;
继承自
Error.message
名称
name: string;
继承自
Error.name
堆栈?
optional stack: string;
继承自
Error.stack
类型
type: ErrorType;
错误类型。用于在日志中识别错误。
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
格式化堆栈跟踪的可选覆盖
参见
https://v8.node.org.cn/docs/stack-trace-api#customizing-stack-traces
参数
参数 | 类型 |
---|---|
err | Error |
堆栈跟踪 | CallSite [] |
返回
任何
继承自
Error.prepareStackTrace
stackTraceLimit
static stackTraceLimit: number;
继承自
Error.stackTraceLimit
方法
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
在目标对象上创建 .stack 属性
参数
参数 | 类型 |
---|---|
targetObject | 对象 |
constructorOpt ? | 功能 |
返回
无效
继承自
Error.captureStackTrace
CredentialsSignin
可以从 Credentials 提供程序的 authorize
回调中抛出。当在 authorize
回调中发生错误时,会发生两件事
- 用户被重定向到登录页面,URL 中带有
error=CredentialsSignin&code=credentials
。code
是可配置的。 - 如果您在处理表单操作的服务器端框架中抛出此错误,则会抛出此错误,而不是重定向用户,因此您需要处理。
扩展
构造函数
new CredentialsSignin(message, errorOptions)
new CredentialsSignin(message?, errorOptions?): CredentialsSignin
参数
参数 | 类型 |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
返回
继承自
属性
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
类型声明
err?
optional err: Error;
继承自
代码
code: string;
在重定向 URL 的 code
查询参数中设置的错误代码。
⚠ 注意:此属性将包含在 URL 中,因此请确保它不会暗示敏感错误。
如果需要调试,完整的错误始终记录在服务器上。
通常,我们不建议特别暗示用户是否使用了错误的用户名或密码,而是尝试使用“无效凭据”之类的内容。
消息
message: string;
继承自
名称
name: string;
继承自
堆栈?
optional stack: string;
继承自
类型
type: ErrorType;
错误类型。用于在日志中识别错误。
继承自
种类
static kind: string;
继承自
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
格式化堆栈跟踪的可选覆盖
参见
https://v8.node.org.cn/docs/stack-trace-api#customizing-stack-traces
参数
参数 | 类型 |
---|---|
err | Error |
堆栈跟踪 | CallSite [] |
返回
任何
继承自
stackTraceLimit
static stackTraceLimit: number;
继承自
类型
static type: string;
方法
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
在目标对象上创建 .stack 属性
参数
参数 | 类型 |
---|---|
targetObject | 对象 |
constructorOpt ? | 功能 |
返回
无效
继承自
帐户
通常包含有关所用提供程序的信息,并且还扩展了 TokenSet
,它是 OAuth 提供程序返回的不同令牌。
扩展
Partial
<TokenEndpointResponse
>
属性
access_token?
optional readonly access_token: string;
继承自
Partial.access_token
authorization_details?
optional readonly authorization_details: AuthorizationDetails[];
继承自
Partial.authorization_details
expires_at?
optional expires_at: number;
基于 TokenEndpointResponse.expires_in 计算的值。
它是 TokenEndpointResponse.access_token 过期的绝对时间戳(以秒为单位)。
此值可用于实现令牌轮换以及 TokenEndpointResponse.refresh_token。
参见
- https://authjs.oauth.ac.cn/guides/refresh-token-rotation#database-strategy
- https://www.rfc-editor.org/rfc/rfc6749#section-5.1
expires_in?
optional readonly expires_in: number;
继承自
Partial.expires_in
id_token?
optional readonly id_token: string;
继承自
Partial.id_token
提供程序
provider: string;
此帐户的提供程序 ID。例如,“google”。在 https://authjs.oauth.ac.cn/reference/core/providers 查看完整列表
providerAccountId
providerAccountId: string;
此值取决于用于创建帐户的提供程序类型。
- oauth/oidc:OAuth 帐户的 ID,从
profile()
回调返回。 - 电子邮件:用户的电子邮件地址。
- 凭据:从
authorize()
回调返回的id
refresh_token?
optional readonly refresh_token: string;
继承自
Partial.refresh_token
scope?
optional readonly scope: string;
继承自
Partial.scope
token_type?
optional readonly token_type: Lowercase<string>;
注意:由于值不区分大小写,因此始终以小写形式返回
继承自
Partial.token_type
type
type: ProviderType;
此帐户的提供程序类型
userId?
optional userId: string;
此帐户所属用户的 ID
查看
https://authjs.oauth.ac.cn/reference/core/adapters#adapteruser
DefaultSession
扩展自
属性
expires
expires: string;
user?
optional user: User;
Profile
从您的 OAuth 提供程序返回的用户资料。
查看
https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
Indexable
[claim
: string
]: unknown
属性
address?
optional address: null | {
country: null | string;
formatted: null | string;
locality: null | string;
postal_code: null | string;
region: null | string;
street_address: null | string;
};
birthdate?
optional birthdate: null | string;
email?
optional email: null | string;
email_verified?
optional email_verified: null | boolean;
family_name?
optional family_name: null | string;
gender?
optional gender: null | string;
given_name?
optional given_name: null | string;
id?
optional id: null | string;
locale?
optional locale: null | string;
middle_name?
optional middle_name: null | string;
name?
optional name: null | string;
nickname?
optional nickname: null | string;
phone_number?
optional phone_number: null | string;
picture?
optional picture: any;
preferred_username?
optional preferred_username: null | string;
profile?
optional profile: null | string;
sub?
optional sub: null | string;
updated_at?
optional updated_at: null | string | number | Date;
website?
optional website: null | string;
zoneinfo?
optional zoneinfo: null | string;
Session
登录用户的活动会话。
扩展自
属性
expires
expires: string;
继承自
user?
optional user: User;
继承自
User
OAuth 提供程序的 profile
回调中返回的对象的形状,在使用数据库时,可在 jwt
和 session
回调中使用,或者作为 session
回调的第二个参数。
扩展自
属性
email?
optional email: null | string;
id?
optional id: string;
image?
optional image: null | string;
name?
optional name: null | string;
ExpressAuthConfig
type ExpressAuthConfig: Omit<AuthConfig, "raw">;
GetSessionResult
type GetSessionResult: Promise<Session | null>;
customFetch
const customFetch: unique symbol;
此选项允许您覆盖提供程序用于直接向提供程序的 OAuth 端点发出请求的默认 fetch
函数。使用不当会导致安全问题。
它可用于支持企业代理、自定义 fetch 库、缓存发现端点、添加用于测试的模拟、记录、为不符合规范的提供程序设置自定义标头/参数等。
示例
import { Auth, customFetch } from "@auth/core"
import GitHub from "@auth/core/providers/github"
const dispatcher = new ProxyAgent("my.proxy.server")
function proxy(...args: Parameters<typeof fetch>): ReturnType<typeof fetch> {
return undici(args[0], { ...(args[1] ?? {}), dispatcher })
}
const response = await Auth(request, {
providers: [GitHub({ [customFetch]: proxy })]
})
查看
- https://undici.nodejs.org/#/docs/api/ProxyAgent?id=example-basic-proxy-request-with-local-agent-dispatcher
- https://authjs.oauth.ac.cn/guides/corporate-proxy
ExpressAuth()
ExpressAuth(config): (req, res, next) => Promise<void>
参数
参数 | 类型 |
---|---|
config | ExpressAuthConfig |
返回
功能
参数
参数 类型 req
Request
<ParamsDictionary
,any
,any
,ParsedQs
,Record
<string
,any
>>res
Response
<any
,Record
<string
,any
>>next
NextFunction
返回
Promise
<void
>
getSession()
getSession(req, config): GetSessionResult
参数
参数 | 类型 |
---|---|
req | Request <ParamsDictionary , any , any , ParsedQs , Record <string , any >> |
config | ExpressAuthConfig |