英文:
Codeigniter 4 - Shield: What is the workflow for creating new users?
问题
I have been playing around with CI4 and Shield for authentication and authorization. There is very little information out there on the workflow for registering new users and how to notify the user that they have been registered into the app. Any help would be appreciated?
Here is my controller function so far:
// Add a member
public function add_member()
{
$data = [];
//$users = model('UserModel');
if ($this->request->getMethod() == 'post') {
$rules = [
//'membership_status' =>
'firstname' => 'required|min_length[3]|max_length[50]',
'lastname' => 'required|min_length[3]|max_length[50]',
'prefered_name' => 'min_length[3]|max_length[50]',
'gender' => 'required|min_length[3]|max_length[25]',
'date_of_birth' => 'required|valid_date',
'address_1' => 'required|min_length[3]|max_length[100]',
'address_2' => 'required|min_length[3]|max_length[100]',
'postal_code' => 'required|min_length[3]|max_length[10]|integer',
'city' => 'required|min_length[3]|max_length[50]',
'home_phone' => 'min_length[3]|max_length[50]',
'work_phone' => 'min_length[3]|max_length[50]',
'mobile' => 'required_without[home_phone,work_phone]|min_length[3]|max_length[50]',
'consent' => 'min_length[2]|max_length[50]',
//'email' => 'required|min_length[6]|max_length[50]|valid_email',
];
if (!$this->validate($rules)) {
$data['validation'] = $this->validator;
$this->session->set('Details', $_POST);
//dd($_SESSION);
} else {
$newData = [
//'id' => $id,
'membership_status' => 'Active',
'firstname' => $this->request->getVar('firstname', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'lastname' => $this->request->getVar('lastname', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'prefered_name' => $this->request->getVar('prefered_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'date_joined' => date('Y-m-d'),
'gender' => $this->request->getVar('gender', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'date_of_birth' => $this->request->getVar('date_of_birth'),
'address_1' => $this->request->getVar('address_1', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'address_2' => $this->request->getVar('address_2', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'postal_code' => $this->request->getVar('postal_code', FILTER_SANITIZE_NUMBER_INT),
'city' => $this->request->getVar('city', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'home_phone' => $this->request->getVar('home_phone', FILTER_SANITIZE_NUMBER_INT),
'work_phone' => $this->request->getVar('work_phone', FILTER_SANITIZE_NUMBER_INT),
'mobile' => $this->request->getVar('mobile', FILTER_SANITIZE_NUMBER_INT),
'consent' => $this->request->getVar('consent'),
//'email' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL)
];
$user = new User([
'username' => NULL,
'email' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL),
'password' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL),
]);
$this->users->save($user);
$newData['id'] = $this->users->getInsertID();
// To get the complete user object with ID, we need to get from the database
$user = $this->users->findById($this->users->getInsertID());
// Add to the default group
$this->users->addToDefaultGroup($user);
$this->users->save($newData);
$userEmail['email'] = $user->getEmail();
// Send the user an email with the code
$email = emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
$email->setTo($user->email);
$email->setSubject(lang('DojoApp.mailSubject'));
$email->setMessage($this->view('email/add_new_user_email', $userEmail));
if ($email->send(false) === false) {
log_message('error', $email->printDebugger(['headers']));
return redirect()->route('login')->with('error', lang('Auth.unableSendEmailToUser', [$user->email]));
}
// Clear the email
$email->clear();
$this->session->setFlashdata('success', 'Successfully added new member information');
return redirect()->to('/admin/members');
}
}
echo view('templates/header');
echo view('admin/left_nav_bar');
echo view('admin/add_member', $data);
echo view('admin/left_nav_bar_closure');
echo view('admin/javascript');
echo view('templates/footer');
} here
No information on the topic internet wide.
英文:
I have been playing around with CI4 and Shield for authentication and authorisation. There is very little information out there on the work flow for registering new users and how to notify the user that they have been registered into the app. Any help would appreciated?
Here is my controller function so far:
type// Add a member
public function add_member()
{
$data = [];
//$users = model('UserModel');
if ($this->request->getMethod() == 'post') {
$rules = [
//'membership_status' =>
'firstname' => 'required|min_length[3]|max_length[50]',
'lastname' => 'required|min_length[3]|max_length[50]',
'prefered_name' => 'min_length[3]|max_length[50]',
'gender' => 'required|min_length[3]|max_length[25]',
'date_of_birth' => 'required|valid_date',
'address_1' => 'required|min_length[3]|max_length[100]',
'address_2' => 'required|min_length[3]|max_length[100]',
'postal_code' => 'required|min_length[3]|max_length[10]|integer',
'city' => 'required|min_length[3]|max_length[50]',
'home_phone' => 'min_length[3]|max_length[50]',
'work_phone' => 'min_length[3]|max_length[50]',
'mobile' => 'required_without[home_phone,work_phone]|min_length[3]|max_length[50]',
'consent' => 'min_length[2]|max_length[50]',
//'email' => 'required|min_length[6]|max_length[50]|valid_email',
];
if (!$this->validate($rules)) {
$data['validation'] = $this->validator;
$this->session->set('Details', $_POST);
//dd($_SESSION);
} else {
$newData = [
//'id' => $id,
'membership_status' => 'Active',
'firstname' => $this->request->getVar('firstname', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'lastname' => $this->request->getVar('lastname', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'prefered_name' => $this->request->getVar('prefered_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'date_joined' => date('Y-m-d'),
'gender' => $this->request->getVar('gender', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'date_of_birth' => $this->request->getVar('date_of_birth'),
'address_1' => $this->request->getVar('address_1', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'address_2' => $this->request->getVar('address_2', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'postal_code' => $this->request->getVar('postal_code', FILTER_SANITIZE_NUMBER_INT),
'city' => $this->request->getVar('city', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'home_phone' => $this->request->getVar('home_phone', FILTER_SANITIZE_NUMBER_INT),
'work_phone' => $this->request->getVar('work_phone', FILTER_SANITIZE_NUMBER_INT),
'mobile' => $this->request->getVar('mobile', FILTER_SANITIZE_NUMBER_INT),
'consent' => $this->request->getVar('consent'),
//'email' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL)
];
$user = new User([
'username' => NULL,
'email' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL),
'password' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL),
]);
$this->users->save($user);
$newData['id'] = $this->users->getInsertID();
// To get the complete user object with ID, we need to get from the database
$user = $this->users->findById($this->users->getInsertID());
// Add to default group
$this->users->addToDefaultGroup($user);
$this->users->save($newData);
$userEmail['email'] = $user->getEmail();
// Send the user an email with the code
$email = emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
$email->setTo($user->email);
$email->setSubject(lang('DojoApp.mailSubject'));
$email->setMessage($this->view('email/add_new_user_email', $userEmail));
if ($email->send(false) === false) {
log_message('error', $email->printDebugger(['headers']));
return redirect()->route('login')->with('error', lang('Auth.unableSendEmailToUser', [$user->email]));
}
// Clear the email
$email->clear();
$this->session->setFlashdata('success', 'Successfuly added new member information');
return redirect()->to('/admin/members');
}
}
echo view('templates/header');
echo view('admin/left_nav_bar');
echo view('admin/add_member', $data);
echo view('admin/left_nav_bar_closure');
echo view('admin/javascript');
echo view('templates/footer');
} here
No information on the topic internet wide.
答案1
得分: 2
以下是翻译好的内容:
看起来你可能没有在正确的地方查找这些信息。
第一步:确保你已经完成了设置 - Composer 将是你最佳的选择
1. [安装链接][1]
2. [设置链接][2]
使用这个[链接][3],你可以查看添加用户的流程。看起来你可能错过了以下的两行代码。这是从链接中摘录出来的一部分,你可能在搜索时忽略了它:
```php
use CodeIgniter\Shield\Entities\User;
use CodeIgniter\Events\Events;
// 获取用户提供程序(默认情况下是 UserModel)
$users = auth()->getProvider();
$user = new User([
'username' => 'foo-bar',
'email' => 'foo.bar@example.com',
'password' => 'secret plain text password',
]);
$users->save($user);
// 要获取具有 ID 的完整用户对象,我们需要从数据库中获取
$user = $users->findById($users->getInsertID());
// 添加到默认组
$users->addToDefaultGroup($user);
一旦你使用上述方法或Shield提供的默认注册表单添加了用户,将会向新用户发送一封电子邮件。以下是描述所需操作的同一网站部分:
注意:你需要配置app/Config/Email.php来允许Shield发送电子邮件。查看安装。
默认情况下,一旦用户注册,他们就有一个可以使用的活动帐户。你可以在Auth配置文件中启用Shield内置的基于电子邮件的激活流程。
public array $actions = [
'register' => \CodeIgniter\Shield\Authentication\Actions\EmailActivator::class,
'login' => null,
];
关于身份验证操作的更多信息可以在这里找到。这将允许你根据需要进行更多配置,并定义了Shield提供的两种操作。
好的,让我们开始吧!
app/Config/Events.php
我们需要添加一个事件来向新用户发送电子邮件。
....
use CodeIgniter\I18n\Time;
use CodeIgniter\Shield\Exceptions\LogicException;
use CodeIgniter\Shield\Exceptions\RuntimeException;
// 注意,我从控制器传递了两个变量$user和$tmpPass
// 我将强制用户在首次登录时更改密码
Events::on('newRegistration', static function ($user, $tmpPass) {
$userEmail = $user->email;
if ($userEmail === null) {
throw new LogicException(
'Email Activation needs user email address. user_id: ' . $user->id
);
}
$date = Time::now()->toDateTimeString();
// 发送电子邮件
$email = emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
$email->setTo($userEmail);
$email->setSubject(lang('Auth.emailActivateSubject'));
$email->setMessage(view(setting('Auth.views')['email_manual_activate_email'], ['userEmail' => $userEmail,'tmpPass' => $tmpPass, 'date' => $date]));
if ($email->send(false) === false) {
throw new RuntimeException('Cannot send email for user: ' . $user->email . "\n" . $email->printDebugger(['headers']));
}
// 清除电子邮件
$email->clear();
});
app/Controllers/Users.php
use \CodeIgniter\Events\Events;
use \CodeIgniter\Config\Factories;
// 根据需要进行修改,我使用Ajax...
public function add() {
checkAjax();
if (!$this->user->hasPermission('users.create')) {
$response['success'] = false;
$response['messages'] = lang("App.invalid_permission");
return $this->response->setJSON($response);
}
$response = array();
$fields['username'] = $this->request->getPost('username');
$fields['password'] = $this->request->getPost('password');
$fields['email'] = $this->request->getPost('email');
$fields['group'] = $this->request->getPost('group');
$this->validation->setRules([
'username' => ['label' => 'Username', 'rules' => 'required|max_length[30]|min_length[3]|regex_match[/\A[a-zA-Z0-9\.]+\z/]|is_unique[users.username,id,{id}]'],
'password' => ['label' => 'Password', 'rules' => 'required|min_length[8]'],
'email' => ['label' => 'Email Address', 'rules' => 'required|valid_email|is_unique[auth_identities.secret,id,{id}]'],
'group' => ['label' => 'Group', 'rules' => 'required'],
]);
if ($this->validation->run($fields) == FALSE) {
$response['success'] = false;
$response['messages'] = $this->validation->getErrors(); //Show Error in Input Form
} else {
$users = auth()->getProvider();
$user = new User([
'username' => $fields['username'],
'email' => $fields['email'],
'password' => $fields['password'],
'status' => 'OFF',
'status_message' => 'New User',
]);
// 保存具有上述信息的用户
$users->save($user);
// 获取新ID,因为我们仍然有工作要做
$user = $users->findById($users->getInsertID());
// 设置标志以使用户在首次登录时更改密码
$user->forcePasswordReset();
// 确保这是用户的唯一组
$user->syncGroups($fields['group']);
// 在这里执行额外的工作...
$actionClass = setting('Auth.actions')['register'] ?? null;
$action = Factories::actions($actionClass)->createIdentity($user);
$code = $action; // 尽管设置了,但目前不需要这个
$tmpPass = $fields['password'];
// 触发我们的新事件并发送这两个变量
$confirm = Events::trigger('newRegistration', $user, $tmpPass);
// 如果一切顺利,通知管理员已添加
<details>
<summary>英文:</summary>
Looks like you might not be looking in the right place for this.
****************
**FIRST: Make sure you have completed the setup - Composer will be your best option**
****************
1. **[Installation Link][1]**
2. **[Setup Link][2]**
Using this [LINK][3] you can see the flow for adding users. Looks like you are missing the 2 lines below: Here is the snippet from that link you may have overlooked during your search:
```php
use CodeIgniter\Shield\Entities\User;
use CodeIgniter\Events\Events;
// Get the User Provider (UserModel by default)
$users = auth()->getProvider();
$user = new User([
'username' => 'foo-bar',
'email' => 'foo.bar@example.com',
'password' => 'secret plain text password',
]);
$users->save($user);
// To get the complete user object with ID, we need to get from the database
$user = $users->findById($users->getInsertID());
// Add to default group
$users->addToDefaultGroup($user);
Once you have added the user using the above method or the default registration form provided by Shield, an email will get sent to the new user. Below is the section on the same site describing the actions needed:
> Note You need to configure app/Config/Email.php to allow Shield to send emails. See Installation.
By default, once a user registers they have an active account that can be used. You can enable Shield's built-in, email-based activation flow within the Auth config file.
public array $actions = [
'register' => \CodeIgniter\Shield\Authentication\Actions\EmailActivator::class,
'login' => null,
];
Additional information on Authentication Actions can be found here. This will allow you to configure more if needed and defines the two provided by Shield.
Ok, Let's get to work!
app/Config/Events.php
We need to add an event to send the new user an email
....
use CodeIgniter\I18n\Time;
use CodeIgniter\Shield\Exceptions\LogicException;
use CodeIgniter\Shield\Exceptions\RuntimeException;
// notice I am passing two variables from the controller $user and $tmpPass
// I will force the user to change password on first login
Events::on('newRegistration', static function ($user, $tmpPass) {
$userEmail = $user->email;
if ($userEmail === null) {
throw new LogicException(
'Email Activation needs user email address. user_id: ' . $user->id
);
}
$date = Time::now()->toDateTimeString();
// Send the email
$email = emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
$email->setTo($userEmail);
$email->setSubject(lang('Auth.emailActivateSubject'));
$email->setMessage(view(setting('Auth.views')['email_manual_activate_email'], ['userEmail' => $userEmail,'tmpPass' => $tmpPass, 'date' => $date]));
if ($email->send(false) === false) {
throw new RuntimeException('Cannot send email for user: ' . $user->email . "\n" . $email->printDebugger(['headers']));
}
// Clear the email
$email->clear();
});
app/Controllers/Users.php
use \CodeIgniter\Events\Events;
use \CodeIgniter\Config\Factories;
// modify however you want. I use Ajax...
public function add() {
checkAjax();
if (!$this->user->hasPermission('users.create')) {
$response['success'] = false;
$response['messages'] = lang("App.invalid_permission");
return $this->response->setJSON($response);
}
$response = array();
$fields['username'] = $this->request->getPost('username');
$fields['password'] = $this->request->getPost('password');
$fields['email'] = $this->request->getPost('email');
$fields['group'] = $this->request->getPost('group');
$this->validation->setRules([
'username' => ['label' => 'Username', 'rules' => 'required|max_length[30]|min_length[3]|regex_match[/\A[a-zA-Z0-9\.]+\z/]|is_unique[users.username,id,{id}]'],
'password' => ['label' => 'Password', 'rules' => 'required|min_length[8]'],
'email' => ['label' => 'Email Address', 'rules' => 'required|valid_email|is_unique[auth_identities.secret,id,{id}]'],
'group' => ['label' => 'Group', 'rules' => 'required'],
]);
if ($this->validation->run($fields) == FALSE) {
$response['success'] = false;
$response['messages'] = $this->validation->getErrors(); //Show Error in Input Form
} else {
$users = auth()->getProvider();
$user = new User([
'username' => $fields['username'],
'email' => $fields['email'],
'password' => $fields['password'],
'status' => 'OFF',
'status_message' => 'New User',
]);
// save the user with the above information
$users->save($user);
// get the new ID as we still have work to do
$user = $users->findById($users->getInsertID());
// set the flag to make user change password on first login
$user->forcePasswordReset();
// make sure this is the only group(s) for the user
$user->syncGroups($fields['group']);
// Additional work done here..
$actionClass = setting('Auth.actions')['register'] ?? null;
$action = Factories::actions($actionClass)->createIdentity($user);
$code = $action; // do not need this yet though it is set
$tmpPass = $fields['password'];
// trigger our new Event and send the two variables
$confirm = Events::trigger('newRegistration', $user, $tmpPass);
// if eveything went well, notifuy the Admin the user has been added and email sent
if ($confirm) {
$response['success'] = true;
$response['messages'] = lang("App.insert-success");
} else {
$response['success'] = false;
$response['messages'] = lang("App.insert-error");
}
}
return $this->response->setJSON($response);
}
email template -> CodeIgniter\Shield\Views\Email\email_manual_activate_email
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<head>
<meta name="x-apple-disable-message-reformatting">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title><?= lang('Auth.emailActivateSubject') ?></title>
</head>
<body>
<p><?= lang('App.emailActivateMail') ?></p>
<div style="text-align: center">
<h3><?= site_url(); ?></h3>
<p>User ID: <?= $userEmail?></p>
<p>Temporary Password: <?= $tmpPass; ?></p>
</div>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
<tbody>
<tr>
<td style="line-height: 20px; font-size: 20px; width: 100%; height: 20px; margin: 0;" align="left" width="100%" height="20">
&#160;
</td>
</tr>
</tbody>
</table>
<b><?= lang('Auth.emailInfo') ?></b>
<p><?= lang('Auth.emailDate') ?> <?= esc($date) ?><br>
Email System Generated for a New User.</p>
</body>
</html>
Make sure you add this line in app/Config/Auth.php
public array $views = [
'email_manual_activate_email' => '\CodeIgniter\Shield\Views\Email\email_manual_activate_email',
];
Now your new users will receive an email when you set them up, even if
$allowRegistration = false;
Once they login for the first time, it will also send them a new code. Verifying the code will send them to wherever you have the force_reset redirect set to.
With all of the extra data you are entering into the tables, you can either expand the users table, or create a new table. More information on that here with code to assist.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论