CarefreeCMS 文档CarefreeCMS 文档
指南
  • 内容管理
  • 多站点管理
  • AI文章生成
  • SEO优化
  • 静态化生成
API
  • FAQ
  • 更新日志
  • 贡献指南
  • v1.3.0
  • v1.2.0
  • v1.1.0
GitHub
指南
  • 内容管理
  • 多站点管理
  • AI文章生成
  • SEO优化
  • 静态化生成
API
  • FAQ
  • 更新日志
  • 贡献指南
  • v1.3.0
  • v1.2.0
  • v1.1.0
GitHub
  • 开始使用

    • 介绍
    • 安装指南
    • 快速开始
    • 系统配置
  • 基础功能

    • 文章管理
    • 分类管理
    • 标签管理
    • 单页管理
    • 媒体库
  • 高级功能

    • 模板开发
    • 静态化生成
    • 搜索功能
    • 权限管理
    • 用户管理
  • AI 功能

    • AI 服务商配置
    • AI 模型配置
    • 提示词工程
  • 系统管理

    • 定时任务
    • 日志管理
    • 安全指南
    • 性能优化

用户管理

本文介绍 CarefreeCMS 的用户管理功能和最佳实践。

用户体系

用户类型

CarefreeCMS 支持多种用户类型:

  • 管理员:后台管理权限
  • 编辑:内容创作和编辑
  • 审核员:内容审核
  • 普通用户:前台注册用户

用户字段

// 用户表结构
[
    'id' => '用户ID',
    'username' => '用户名',
    'email' => '邮箱',
    'mobile' => '手机号',
    'password' => '密码(加密)',
    'nickname' => '昵称',
    'avatar' => '头像',
    'role_id' => '角色ID',
    'status' => '状态(normal/disabled)',
    'last_login_time' => '最后登录时间',
    'last_login_ip' => '最后登录IP',
    'create_time' => '创建时间',
    'update_time' => '更新时间',
]

用户注册

前台注册

注册页面

<form action="/api/auth/register" method="POST">
    <input type="text" name="username" required>
    <input type="email" name="email" required>
    <input type="password" name="password" required>
    <input type="password" name="password_confirm" required>
    <button type="submit">注册</button>
</form>

注册逻辑

class AuthController
{
    public function register()
    {
        $data = request()->post();

        // 验证
        $validate = new UserValidate();
        if (!$validate->scene('register')->check($data)) {
            return json(['code' => 400, 'msg' => $validate->getError()]);
        }

        // 检查用户名是否存在
        if (User::where('username', $data['username'])->find()) {
            return json(['code' => 400, 'msg' => '用户名已存在']);
        }

        // 创建用户
        $user = User::create([
            'username' => $data['username'],
            'email' => $data['email'],
            'password' => password_hash($data['password'], PASSWORD_BCRYPT),
            'role_id' => 3, // 普通用户
            'status' => 'normal',
        ]);

        // 发送欢迎邮件
        Queue::push('app\job\SendEmail', [
            'email' => $user->email,
            'subject' => '欢迎注册',
            'content' => '...',
        ]);

        return json(['code' => 200, 'msg' => '注册成功']);
    }
}

邮箱验证

发送验证邮件

public function sendVerifyEmail($userId)
{
    $user = User::find($userId);

    // 生成验证码
    $code = md5($user->id . $user->email . time());

    // 保存验证码
    Cache::set("verify_email:$userId", $code, 3600);

    // 发送邮件
    $link = url('auth/verify', ['id' => $userId, 'code' => $code]);
    Queue::push('app\job\SendEmail', [
        'email' => $user->email,
        'subject' => '验证邮箱',
        'content' => "请点击链接验证邮箱:$link",
    ]);
}

public function verifyEmail()
{
    $userId = request()->param('id');
    $code = request()->param('code');

    // 验证码校验
    $savedCode = Cache::get("verify_email:$userId");
    if ($code !== $savedCode) {
        return '验证码无效';
    }

    // 更新用户状态
    User::where('id', $userId)->update(['email_verified' => 1]);
    Cache::delete("verify_email:$userId");

    return '邮箱验证成功';
}

手机验证

public function sendSmsCode()
{
    $mobile = request()->post('mobile');

    // 生成验证码
    $code = rand(100000, 999999);

    // 保存验证码
    Cache::set("sms_code:$mobile", $code, 300);

    // 发送短信(接入短信服务商)
    $sms = new SmsService();
    $sms->send($mobile, "您的验证码是:$code");

    return json(['code' => 200, 'msg' => '验证码已发送']);
}

public function registerWithMobile()
{
    $mobile = request()->post('mobile');
    $code = request()->post('code');

    // 验证码校验
    $savedCode = Cache::get("sms_code:$mobile");
    if ($code != $savedCode) {
        return json(['code' => 400, 'msg' => '验证码错误']);
    }

    // 创建用户
    $user = User::create([
        'mobile' => $mobile,
        'username' => $mobile,
        'mobile_verified' => 1,
    ]);

    Cache::delete("sms_code:$mobile");

    return json(['code' => 200, 'msg' => '注册成功']);
}

用户登录

账号密码登录

public function login()
{
    $username = request()->post('username');
    $password = request()->post('password');

    // 查找用户
    $user = User::where('username', $username)
        ->whereOr('email', $username)
        ->find();

    if (!$user) {
        return json(['code' => 400, 'msg' => '用户不存在']);
    }

    // 验证密码
    if (!password_verify($password, $user->password)) {
        return json(['code' => 400, 'msg' => '密码错误']);
    }

    // 检查状态
    if ($user->status !== 'normal') {
        return json(['code' => 400, 'msg' => '账号已被禁用']);
    }

    // 更新登录信息
    $user->last_login_time = time();
    $user->last_login_ip = request()->ip();
    $user->save();

    // 生成 Token
    $token = $this->generateToken($user);

    return json([
        'code' => 200,
        'msg' => '登录成功',
        'data' => [
            'token' => $token,
            'user' => $user->hidden(['password']),
        ],
    ]);
}

第三方登录

微信登录

public function wechatLogin()
{
    $code = request()->param('code');

    // 获取 access_token
    $response = $this->getWechatAccessToken($code);
    $openid = $response['openid'];

    // 查找或创建用户
    $user = User::where('wechat_openid', $openid)->find();

    if (!$user) {
        // 获取用户信息
        $userInfo = $this->getWechatUserInfo($response['access_token'], $openid);

        // 创建用户
        $user = User::create([
            'wechat_openid' => $openid,
            'nickname' => $userInfo['nickname'],
            'avatar' => $userInfo['headimgurl'],
            'username' => 'wx_' . $openid,
        ]);
    }

    // 生成 Token
    $token = $this->generateToken($user);

    return json([
        'code' => 200,
        'data' => ['token' => $token],
    ]);
}

GitHub 登录

public function githubLogin()
{
    $code = request()->param('code');

    // OAuth 授权
    $token = $this->getGithubAccessToken($code);
    $userInfo = $this->getGithubUserInfo($token);

    // 查找或创建用户
    $user = User::where('github_id', $userInfo['id'])->find();

    if (!$user) {
        $user = User::create([
            'github_id' => $userInfo['id'],
            'username' => $userInfo['login'],
            'nickname' => $userInfo['name'],
            'avatar' => $userInfo['avatar_url'],
            'email' => $userInfo['email'],
        ]);
    }

    $token = $this->generateToken($user);

    return json(['code' => 200, 'data' => ['token' => $token]]);
}

记住登录

public function login()
{
    // ... 登录逻辑

    $remember = request()->post('remember', false);

    if ($remember) {
        // 生成长期 token
        $refreshToken = $this->generateRefreshToken($user);

        // 保存到数据库
        UserToken::create([
            'user_id' => $user->id,
            'token' => $refreshToken,
            'expire_time' => time() + 30 * 86400, // 30天
        ]);

        return json([
            'code' => 200,
            'data' => [
                'token' => $token,
                'refresh_token' => $refreshToken,
            ],
        ]);
    }

    return json(['code' => 200, 'data' => ['token' => $token]]);
}

用户信息管理

查看个人信息

public function profile()
{
    $user = request()->user;

    return json([
        'code' => 200,
        'data' => $user->hidden(['password']),
    ]);
}

修改个人信息

public function updateProfile()
{
    $user = request()->user;
    $data = request()->post();

    // 允许修改的字段
    $allowedFields = ['nickname', 'avatar', 'email', 'mobile'];

    foreach ($allowedFields as $field) {
        if (isset($data[$field])) {
            $user->$field = $data[$field];
        }
    }

    $user->save();

    return json(['code' => 200, 'msg' => '修改成功']);
}

修改密码

public function changePassword()
{
    $user = request()->user;
    $oldPassword = request()->post('old_password');
    $newPassword = request()->post('new_password');

    // 验证旧密码
    if (!password_verify($oldPassword, $user->password)) {
        return json(['code' => 400, 'msg' => '原密码错误']);
    }

    // 更新密码
    $user->password = password_hash($newPassword, PASSWORD_BCRYPT);
    $user->save();

    // 清除所有 token
    UserToken::where('user_id', $user->id)->delete();

    return json(['code' => 200, 'msg' => '密码修改成功,请重新登录']);
}

找回密码

public function forgotPassword()
{
    $email = request()->post('email');

    $user = User::where('email', $email)->find();
    if (!$user) {
        return json(['code' => 400, 'msg' => '邮箱不存在']);
    }

    // 生成重置链接
    $token = md5($user->id . $email . time());
    Cache::set("reset_password:$token", $user->id, 3600);

    // 发送邮件
    $link = url('auth/reset-password', ['token' => $token]);
    Queue::push('app\job\SendEmail', [
        'email' => $email,
        'subject' => '重置密码',
        'content' => "请点击链接重置密码:$link",
    ]);

    return json(['code' => 200, 'msg' => '重置链接已发送']);
}

public function resetPassword()
{
    $token = request()->param('token');
    $newPassword = request()->post('password');

    $userId = Cache::get("reset_password:$token");
    if (!$userId) {
        return json(['code' => 400, 'msg' => '链接已失效']);
    }

    // 更新密码
    User::where('id', $userId)->update([
        'password' => password_hash($newPassword, PASSWORD_BCRYPT),
    ]);

    Cache::delete("reset_password:$token");

    return json(['code' => 200, 'msg' => '密码重置成功']);
}

后台管理

用户列表

public function index()
{
    $keyword = request()->param('keyword', '');
    $status = request()->param('status', '');
    $roleId = request()->param('role_id', '');

    $query = User::with('role');

    if ($keyword) {
        $query->where('username|email|mobile', 'like', "%$keyword%");
    }

    if ($status) {
        $query->where('status', $status);
    }

    if ($roleId) {
        $query->where('role_id', $roleId);
    }

    $users = $query->order('id', 'desc')->paginate(20);

    return view('user/index', ['users' => $users]);
}

添加用户

public function add()
{
    if (request()->isPost()) {
        $data = request()->post();

        $user = User::create([
            'username' => $data['username'],
            'email' => $data['email'],
            'password' => password_hash($data['password'], PASSWORD_BCRYPT),
            'role_id' => $data['role_id'],
            'status' => $data['status'],
        ]);

        return json(['code' => 200, 'msg' => '添加成功']);
    }

    $roles = Role::select();
    return view('user/add', ['roles' => $roles]);
}

编辑用户

public function edit($id)
{
    $user = User::find($id);

    if (request()->isPost()) {
        $data = request()->post();

        $user->username = $data['username'];
        $user->email = $data['email'];
        $user->role_id = $data['role_id'];
        $user->status = $data['status'];

        // 如果修改密码
        if (!empty($data['password'])) {
            $user->password = password_hash($data['password'], PASSWORD_BCRYPT);
        }

        $user->save();

        return json(['code' => 200, 'msg' => '修改成功']);
    }

    $roles = Role::select();
    return view('user/edit', ['user' => $user, 'roles' => $roles]);
}

禁用/启用用户

public function toggleStatus($id)
{
    $user = User::find($id);

    $user->status = $user->status === 'normal' ? 'disabled' : 'normal';
    $user->save();

    // 如果禁用,清除 token
    if ($user->status === 'disabled') {
        UserToken::where('user_id', $id)->delete();
    }

    return json(['code' => 200, 'msg' => '操作成功']);
}

删除用户

public function delete($id)
{
    // 不能删除自己
    if ($id == request()->user->id) {
        return json(['code' => 400, 'msg' => '不能删除当前用户']);
    }

    $user = User::find($id);

    // 删除关联数据
    UserToken::where('user_id', $id)->delete();
    Article::where('user_id', $id)->delete();

    $user->delete();

    return json(['code' => 200, 'msg' => '删除成功']);
}

用户统计

统计数据

public function statistics()
{
    $stats = [
        'total' => User::count(),
        'today' => User::whereTime('create_time', 'today')->count(),
        'week' => User::whereTime('create_time', 'week')->count(),
        'month' => User::whereTime('create_time', 'month')->count(),
        'active' => User::where('status', 'normal')->count(),
        'disabled' => User::where('status', 'disabled')->count(),
    ];

    return json(['code' => 200, 'data' => $stats]);
}

增长趋势

public function trend()
{
    $days = 30;
    $data = [];

    for ($i = $days - 1; $i >= 0; $i--) {
        $date = date('Y-m-d', strtotime("-$i days"));
        $count = User::whereTime('create_time', $date)->count();

        $data[] = [
            'date' => $date,
            'count' => $count,
        ];
    }

    return json(['code' => 200, 'data' => $data]);
}

最佳实践

密码安全

// 强密码策略
public function validatePassword($password)
{
    $config = config('app.password');

    if (strlen($password) < $config['min_length']) {
        throw new Exception('密码长度不足');
    }

    if ($config['require_uppercase'] && !preg_match('/[A-Z]/', $password)) {
        throw new Exception('密码必须包含大写字母');
    }

    if ($config['require_lowercase'] && !preg_match('/[a-z]/', $password)) {
        throw new Exception('密码必须包含小写字母');
    }

    if ($config['require_numbers'] && !preg_match('/[0-9]/', $password)) {
        throw new Exception('密码必须包含数字');
    }

    if ($config['require_special_chars'] && !preg_match('/[^A-Za-z0-9]/', $password)) {
        throw new Exception('密码必须包含特殊字符');
    }
}

防止暴力破解

public function login()
{
    $username = request()->post('username');
    $ip = request()->ip();

    // 检查登录次数
    $key = "login_attempt:$ip";
    $attempts = Cache::get($key, 0);

    if ($attempts >= 5) {
        return json(['code' => 400, 'msg' => '登录失败次数过多,请30分钟后再试']);
    }

    // ... 登录逻辑

    // 登录失败,记录次数
    Cache::set($key, $attempts + 1, 1800);
}

会话管理

// 单设备登录
public function singleLogin($user)
{
    // 删除旧 token
    UserToken::where('user_id', $user->id)->delete();

    // 生成新 token
    return $this->generateToken($user);
}

// 多设备登录
public function multipleLogin($user)
{
    // 限制最多5个设备
    $tokenCount = UserToken::where('user_id', $user->id)->count();

    if ($tokenCount >= 5) {
        // 删除最旧的 token
        UserToken::where('user_id', $user->id)
            ->order('create_time', 'asc')
            ->limit(1)
            ->delete();
    }

    return $this->generateToken($user);
}

相关资源

  • 权限管理
  • 用户 API
  • 安全指南
在 GitHub 上编辑此页
Prev
权限管理