# 用户名 (/docs/plugins/username)

用户名插件



用户名插件是一个轻量级插件，为电子邮件和密码认证器添加了用户名支持。这样用户可以使用用户名而不是电子邮件进行登录。

## 安装 [#安装]

<Steps>
  <Step>
    ### 将插件添加到服务器 [#将插件添加到服务器]

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth"
    import { username } from "better-auth/plugins" // [!code highlight]

    export const auth = betterAuth({
        emailAndPassword: { // [!code highlight]
            enabled: true, // [!code highlight]
        }, // [!code highlight]
        plugins: [ // [!code highlight]
            username() // [!code highlight]
        ] // [!code highlight]
    })
    ```
  </Step>

  <Step>
    ### 迁移数据库 [#迁移数据库]

    运行迁移或生成架构以向数据库添加必要的字段和表。

    <Tabs items="[&#x22;migrate&#x22;, &#x22;generate&#x22;]">
      <Tab value="migrate">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth migrate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>

      <Tab value="generate">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth generate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>
    </Tabs>

    有关手动添加字段的说明，请参见[架构](#schema)部分。
  </Step>

  <Step>
    ### 添加客户端插件 [#添加客户端插件]

    ```ts title="auth-client.ts"
    import { createAuthClient } from "better-auth/client"
    import { usernameClient } from "better-auth/client/plugins" // [!code highlight]

    export const authClient = createAuthClient({
        plugins: [ // [!code highlight]
            usernameClient() // [!code highlight]
        ] // [!code highlight]
    })
    ```
  </Step>
</Steps>

## 用法 [#用法]

### 注册 [#注册]

要使用用户名注册用户，可以使用客户端提供的现有 `signUp.email` 函数。\
`signUp` 函数接受一个新增的 `username` 属性。

**Endpoint:** `POST /sign-up/email`

### Client Side

```ts
const { data, error } = await authClient.signUp.email({
    email: "email@domain.com", // required, 用户的电子邮件。
    name: "Test User", // required, 用户的姓名。
    password: "password1234", // required, 用户的密码。
    username: "test", // 用户的用户名。
    displayUsername: "Test User123", // 可选的用户名显示名称。
});
```

### Server Side

```ts
const data = await auth.api.signUpEmail({
    body: {
        email: "email@domain.com", // required, 用户的电子邮件。
        name: "Test User", // required, 用户的姓名。
        password: "password1234", // required, 用户的密码。
        username: "test", // 用户的用户名。
        displayUsername: "Test User123", // 可选的用户名显示名称。
    },
});
```

### Type Definition

```ts
type signUpEmail = {
    /**
     * 用户的电子邮件。
    */
    email: string = "email@domain.com"
    /**
     * 用户的姓名。
    */
    name: string = "Test User"
    /**
     * 用户的密码。
    */
    password: string = "password1234"
    /**
     * 用户的用户名。
    */
    username?: string = "test"
    /**
     * 可选的用户名显示名称。
    */
    displayUsername?: string = "Test User123"
}
```

<Callout type="info">
  如果仅提供 `username`，则 `displayUsername` 将设置为 `username` 的预标准化版本。你可以在[用户名标准化](#username-normalization)和[显示用户名标准化](#display-username-normalization)部分获取更多详细信息。
</Callout>

### 登录 [#登录]

要使用用户名登录用户，可以使用客户端提供的 `signIn.username` 函数。

**Endpoint:** `POST /sign-in/username`

### Client Side

```ts
const { data, error } = await authClient.signIn.username({
    username: "test", // required, 用户的用户名。
    password: "password1234", // required, 用户的密码。
});
```

### Server Side

```ts
const data = await auth.api.signInUsername({
    body: {
        username: "test", // required, 用户的用户名。
        password: "password1234", // required, 用户的密码。
    },
});
```

### Type Definition

```ts
type signInUsername = {
    /**
     * 用户的用户名。
    */
    username: string = "test"
    /**
     * 用户的密码。
    */
    password: string = "password1234"
}
```

### 更新用户名 [#更新用户名]

要更新用户的用户名，可以使用客户端提供的 `updateUser` 函数。

<Callout type="info">
  如果启用了 `immutableUsername`，用户可以在注册期间设置用户名，或者在尚未拥有用户名的情况下稍后设置，但用户名一旦设置后就无法更改。
</Callout>

**Endpoint:** `POST /update-user`

### Client Side

```ts
const { data, error } = await authClient.updateUser({
    username: "new-username", // 要更新的用户名。
});
```

### Server Side

```ts
const data = await auth.api.updateUser({
    body: {
        username: "new-username", // 要更新的用户名。
    },
});
```

### Type Definition

```ts
type updateUser = {
    /**
     * 要更新的用户名。
    */
    username?: string = "new-username"
}
```

### 检查用户名是否可用 [#检查用户名是否可用]

要检查用户名是否可用，可以使用客户端提供的 `isUsernameAvailable` 函数。

**Endpoint:** `POST /is-username-available`

### Client Side

```ts
const { data: response, error } = await authClient.isUsernameAvailable({
    username: "new-username", // required, 要检查的用户名。
});
if (response?.available) {
    console.log("用户名可用");
} else {
    console.log("用户名不可用");
}
```

### Server Side

```ts
const response = await auth.api.isUsernameAvailable({
    body: {
        username: "new-username", // required, 要检查的用户名。
    },
});
if (response?.available) {
    console.log("用户名可用");
} else {
    console.log("用户名不可用");
}
```

### Type Definition

```ts
type isUsernameAvailable = {
    /**
     * 要检查的用户名。
    */
    username: string = "new-username"
}
```

## 选项 [#选项]

### 最小用户名长度 [#最小用户名长度]

用户名的最小长度。默认为 `3`。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            minUsernameLength: 5
        })
    ]
})
```

### 最大用户名长度 [#最大用户名长度]

用户名的最大长度。默认为 `30`。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            maxUsernameLength: 100
        })
    ]
})
```

### 用户名验证器 [#用户名验证器]

一个验证用户名的函数。如果用户名无效，该函数应返回 `false`。默认情况下，用户名只允许包含字母数字字符、下划线和点。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            usernameValidator: (username) => {
                if (username === "admin") {
                    return false
                }
                return true
            }
        })
    ]
})
```

### 显示用户名验证器 [#显示用户名验证器]

一个验证显示用户名的函数。如果显示用户名无效，该函数应返回 `false`。默认情况下，不对显示用户名进行验证。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            displayUsernameValidator: (displayUsername) => {
                // 只允许字母数字字符、下划线和连字符
                return /^[a-zA-Z0-9_-]+$/.test(displayUsername)
            }
        })
    ]
})
```

### 用户名标准化 [#用户名标准化]

一个用于标准化用户名的函数，或者设置为 `false` 以禁用标准化。

默认情况下，用户名被标准化为小写，例如 "TestUser" 和 "testuser" 被视为相同的用户名。`username` 字段包含标准化（小写）的用户名，而 `displayUsername` 保持原始的用户名。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            usernameNormalization: (username) => {
                return username.toLowerCase()
                    .replaceAll("0", "o")
                    .replaceAll("3", "e")
                    .replaceAll("4", "a");
            }
        })
    ]
})
```

### 显示用户名标准化 [#显示用户名标准化]

一个用于标准化显示用户名的函数，或设置为 `false` 禁用标准化。

默认情况下，显示用户名不进行标准化。当仅提供 `username` 进行注册或更新时，`displayUsername` 会设为原始的 `username`（标准化之前）。你也可以显式地设置 `displayUsername`，该值会被原样保留。如需自定义标准化，请提供一个接受显示用户名为输入并返回标准化结果的函数。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            displayUsernameNormalization: (displayUsername) => displayUsername.toLowerCase(),
        })
    ]
})
```

### 验证顺序 [#验证顺序]

默认情况下，用户名和显示用户名在标准化之前进行验证。你可以通过设置 `validationOrder` 为 `post-normalization` 来改变此行为。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            validationOrder: {
                username: "post-normalization",
                displayUsername: "post-normalization",
            }
        })
    ]
})
```

### 禁用显示用户名 [#禁用显示用户名]

默认情况下，插件会向用户表添加一个单独的 `displayUsername` 字段，用于存储未经标准化的用户名。如果你的应用不需要该字段，请将 `displayUsername` 设置为 `false`。禁用后：

* 用户架构中不会添加 `displayUsername` 字段（不会增加额外的列或迁移）
* 注册或更新期间不会写入 `displayUsername`
* 推断出的用户／会话类型不包含 `displayUsername`
* 用户名标准化会继续正常工作

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            displayUsername: false
        })
    ]
})
```

向客户端插件传入相同的选项，以使客户端推断出的类型与服务器保持一致：

```ts title="auth-client.ts"
import { createAuthClient } from "better-auth/client"
import { usernameClient } from "better-auth/client/plugins"

const authClient = createAuthClient({
    plugins: [
        usernameClient({ displayUsername: false })
    ]
})
```

### 不可变用户名 [#不可变用户名]

默认情况下，用户可以更新其用户名。将 `immutableUsername` 设置为 `true`，以防止用户在用户名设置后更改用户名。

用户仍然可以在注册期间设置用户名，或者在尚未选择用户名的情况下通过之后的个人资料更新来设置用户名。仍然允许更新其他个人资料字段。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    plugins: [
        username({
            immutableUsername: true
        })
    ]
})
```

### 禁用检查用户名是否可用 [#禁用检查用户名是否可用]

默认情况下，插件提供了 `/is-username-available` 接口用于检查用户名是否可用。你可以通过在 better-auth 配置中提供 `disabledPaths` 选项禁用此接口。这对于防止用户名被枚举很有用。

```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { username } from "better-auth/plugins"

const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    disabledPaths: ["/is-username-available"],
    plugins: [
        username()
    ]
})
```

## 架构 [#架构]

该插件要求向用户表添加 2 个字段（设置 [`displayUsername: false`](#disable-display-username) 时会省略 `displayUsername` 字段）：



<DatabaseTable name="user" fields="usernameUserTableFields" />

