我在项目中使用zf2身份验证来验证用户。我将Harib保存在我的用户表中作为用户名,但如果我使用我的用户名Harib,则它接受,或者如果我使用Harib,则不接受,我想删除用户名的大小写敏感性,以便Harib或Harib都可以访问。我如何解决此问题?
这是我的代码:
public function loginAction()
{
$this->layout('layout/login-layout.phtml');
$login_error = false;
$loginForm = new LoginForm();
$form_elements = json_encode($loginForm->form_elements);
if ($this->request->isPost()) {
$post = $this->request->getPost();
$loginForm->setData($post);
if ($loginForm->isValid()) {
$hashed_string = '';
if(
array_key_exists('hashed_input' , $post) &&
$post['hashed_input'] != '' &&
strpos(urldecode($this->params('redirect')) , 'programdetailrequest') !== false
) {
$hashed_string = $post['hashed_input'];
}
$data = $loginForm->getData();
$authService = $this->getServiceLocator()->get('doctrine.authenticationservice.odm_default');
$adapter = $authService->getAdapter();
$adapter->setIdentityValue($data['username']);
$adapter->setCredentialValue(md5($data['password']));
$authResult = $authService->authenticate();
if($authResult->isValid()){
$identity = $authResult->getIdentity();
if( is_object($identity) && method_exists($identity, 'getData') ){
$user_data = $identity->getData();
$authService->getStorage()->write($identity);
// for remeber checkbox
if ($post['rememberme']) {
$token = new UserToken();
$dm = $this->getServiceLocator()->get('doctrine.documentmanager.odm_default');
//if same user already running from other browser then remove previous token.
$check_token = $dm->getRepository('AdminDocumentUserToken')->findOneBy(array( "user_id.id" => $user_data['id'] ));
if (is_object($check_token) && !is_null($check_token)) {
$remove_token = $dm->createQueryBuilder('AdminDocumentUserToken')
->remove()
->field('id')->equals($check_token->id)
->getQuery()->execute();
}
//create token
$user = $dm->getRepository('AdminDocumentUser')->findOneBy(array( "id" => $user_data['id'] ));
$token->setProperty('user_id', $user);
$token->setProperty('dataentered', new MongoDate());
$dm->persist($token);
$dm->flush($token);
//create cookie
if(is_object($token) && property_exists($token, 'id')){
$time = time() + (60 * 60 * 24 * 30); // 1 month
setcookie('token', $token->getProperty('id'), $time, '/');
}
}
if ($user_data['user_type'] == 'onlinemarketer') {
$this->redirect()->toRoute('admin_program_meta');
} elseif ($user_data['user_type'] == 'bucharestofficemanager') {
$this->redirect()->toRoute('admin_program_detail_request');
} else {
if ($this->params('redirect') && urldecode($this->params('redirect')) !== '/logout/') {
$server_url = $this->getRequest()->getUri()->getScheme() . '://' . $this->getRequest()->getUri()->getHost().urldecode($this->params('redirect') . $hashed_string);
return $this->redirect()->toUrl($server_url);
}
return $this->redirect()->toRoute('admin_index');
}
}
} else {
$identity = false;
$login_error = true;
}
}
}
return new ViewModel(array(
'loginForm' => $loginForm,
'form_elements' =>$form_elements,
'login_error' => $login_error,
));
}
这是我的登录表单代码:
<?php
namespace AdminForm;
use ZendFormForm;
use ZendFormElement;
use ZendInputFilterInputFilterAwareInterface;
use ZendInputFilterInputFilter;
use ZendInputFilterFactory as InputFactory;
class LoginForm extends Form implements InputFilterAwareInterface
{
protected $inputFilter;
public $form_elements = array(
array(
'name' => 'username',
'attributes' => array(
'id' => 'username',
'type' => 'text',
'error_msg' => 'Enter Valid Username',
'data-parsley-required' => 'true',
'data-parsley-pattern' => '^[a-zA-Z0-9_.-]{1,50}$',
'data-parsley-trigger' => 'change'
),
'options' => array(
'label' => 'User Name'
),
'validation' => array(
'required'=>true,
'filters'=> array(
array('name'=>'StripTags'),
array('name'=>'StringTrim')
),
'validators'=>array(
array('name'=>'Regex',
'options'=> array(
'pattern' => '/^[a-z0-9_.-]{1,50}+$/', // contain only a to z 0 to 9 underscore, hypen and space, min 1 max 50
'pattern_js' => '^[a-zA-Z0-9_.-]{1,50}$'
)
)
)
)
),
array(
'name' => 'password',
'attributes' => array(
'id' => 'password',
'type' => 'password',
'error_msg' => 'Enter Valid Password',
'data-parsley-required' => 'true',
'data-parsley-pattern' => '^[a-zA-Z0-9_.-]{6,25}$',
'data-parsley-trigger' => 'change'
),
'options' => array(
'label' => 'Password'
),
'validation' => array(
'required' => true,
'filters'=> array(
array('name'=>'StripTags'),
array('name'=>'StringTrim')
),
'validators'=>array(
array('name'=>'Regex',
'options'=> array(
'pattern' => '/^[a-z0-9_.-]{6,25}+$/', // contain only a to z 0 to 9 underscore, hypen and space, min 1 max 50
'pattern_js' => '^[a-zA-Z0-9_.-]{6,25}$'
)
)
)
)
),
array(
'name' => 'hashed_input',
'attributes' => array(
'type' => 'hidden',
'id' => 'hashed_input',
'value' => ''
)
),
array(
'name' => 'rememberme',
'attributes' => array(
'value' => 1,
'id' => 'rememberme',
'type' => 'Checkbox'
),
'options' => array(
'label' => 'Remember Me',
'use_hidden_element' => false,
)
),
array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Log in',
'id' => 'submitbutton'
)
)
);
public function __construct()
{
parent::__construct('user');
$this->setAttribute('method', 'post');
$this->setAttribute('data-parsley-validate', '');
$this->setAttribute('data-elements', json_encode($this->form_elements));
$this->setAttribute('autocomplete', 'off');
for($i=0;$i<count($this->form_elements);$i++){
$elements=$this->form_elements[$i];
$this->add($elements);
}
}
public function getInputFilter($action=false)
{
if(!$this->inputFilter){
$inputFilter = new InputFilter();
$factory = new InputFactory();
for($i=0;$i<count($this->form_elements);$i++){
if(array_key_exists('validation',$this->form_elements[$i])){
$this->form_elements[$i]['validation']['name']=$this->form_elements[$i]['name'];
$inputFilter->add($factory->createInput( $this->form_elements[$i]['validation'] ));
}
}
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
我们如何删除用户名的大小写敏感性,以便接受Harib或Harib?
在元素user_id
的loginform
中添加一个过滤器StringToLower
。
为此,定义loginform
的类必须实现InputFilterProviderInterface
,并且必须添加getInputFilterSpecification
方法,如下所示:
public function getInputFilterSpecification()
{
return [
'username' => [
'name' => 'username',
'required' => true,
'filters' => [
'name' => 'StringToLower',
'name'=>'StripTags',
'name'=>'StringTrim'
],
validators => [
[
'name'=>'Regex',
'options'=> [
'pattern' => '/^[a-z0-9_.-]{1,50}+$/',
'pattern_js' => '^[a-zA-Z0-9_.-]{1,50}$'
]
]
]
],
'password' => [
'name' => 'password',
'required' => true,
'filters' => [
array('name'=>'StripTags'),
array('name'=>'StringTrim')
],
'validators' => [
[
'name'=>'Regex',
'options'=> [
'pattern' => '/^[a-z0-9_.-]{6,25}+$/',
'pattern_js' => '^[a-zA-Z0-9_.-]{6,25}$'
]
]
]
]
];
}
因此,您可以确信post中返回的值是小写的。
由于您使用的是MongoDB,因此可以使用regex从数据库中获取用户名。
建议1:
在你的例子中,这将是:
db.stuff.find( { foo: /^bar$/i } );
建议2:
您可以使用$options=>i进行不区分大小写的搜索。给出了字符串匹配所需的一些可能的示例。
不区分大小写的精确字符串
db.collection.find({name:{'$regex' : '^string$', '$options' : 'i'}})
包含字符串
db.collection.find({name:{'$regex' : 'string', '$options' : 'i'}})
从字符串开始
db.collection.find({name:{'$regex' : '^string', '$options' : 'i'}})
以字符串结束
db.collection.find({name:{'$regex' : 'string$', '$options' : 'i'}})
不包含字符串
db.collection.find({name:{'$regex' : '^((?!string).)*$', '$options' : 'i'}})
有关MongoDb中regex的更多信息,请点击此处:https://docs.mongodb.com/manual/reference/operator/query/regex/index.html
您可以通过两种方式来实现这一点。您可以创建自定义身份验证适配器,也可以覆盖默认身份验证适配器的方法。我建议重写该方法,这比创建自定义适配器更容易。
这里是方法CredentialTreatmentAdapter::authenticateCreateSelect()
。如果你从zend-authentication
组件中查找该方法的大约94行(zf 2.5),那么你会找到下面的行。
$dbSelect->from($this->tableName)
->columns(['*', $credentialExpression])
// See the making of where clause
->where(new SqlOp($this->identityColumn, '=', $this->identity));
我们将在这里做出改变。现在让我们通过扩展ZendAuthenticationAdapterDbTable
来覆盖该方法。因此,我们将制作一个where子句,同时搜索Harib
或harib
。请参阅以下扩展CustomDbTable::class
。
<?php
namespace DefineYourOwnNamespace;
use ZendAuthenticationAdapterDbTable;
class CustomDbTable extends DbTable
{
protected function authenticateCreateSelect()
{
// build credential expression
if (empty($this->credentialTreatment) || (strpos($this->credentialTreatment, '?') === false)) {
$this->credentialTreatment = '?';
}
$credentialExpression = new SqlExpr(
'(CASE WHEN ?' . ' = ' . $this->credentialTreatment . ' THEN 1 ELSE 0 END) AS ?',
array($this->credentialColumn, $this->credential, 'zend_auth_credential_match'),
array(SqlExpr::TYPE_IDENTIFIER, SqlExpr::TYPE_VALUE, SqlExpr::TYPE_IDENTIFIER)
);
// Here is the catch
$where = new ZendDbSqlWhere();
$where->nest()
->equalTo($this->identityColumn, $this->identity)
->or
->equalTo($this->identityColumn, strtolower($this->identity))
->unnest();
// get select
$dbSelect = clone $this->getDbSelect();
$dbSelect->from($this->tableName)
->columns(array('*', $credentialExpression))
->where($where); // Here we are making our own where clause
return $dbSelect;
}
}
现在,自定义身份验证适配器已准备就绪。您需要在工厂内使用这个来进行身份验证服务,而不是ZendAuthenticationAdapterDbTable
,如下所示
'factories' => array(
// Auth service
'AuthService' => function($sm) {
$dbAdapter = $sm->get('ZendDbAdapterAdapter');
// Use CustomDbTable instead of DbTable here
$customDbTable = new CustomDbTable($dbAdapter, 'tableName', 'usernameColumn', 'passwordColumn', 'MD5(?)');
$authService = new AuthenticationService();
$authService->setAdapter($customDbTable);
return $authService;
},
),
现在一切就绪。每当你在控制器方法中调用这个方法时,应该调用这个被覆盖的方法:
$authResult = $authService->authenticate();
这没有经过测试。所以你可能需要在需要的地方改变。如果需要,请修理。
希望这对你有帮助!