【问题标题】:cakePHP User AuthenitcationcakePHP 用户认证
【发布时间】:2014-02-06 09:30:23
【问题描述】:

我是蛋糕新手,所以非常感谢任何帮助。

我有一个应用程序,使用 CakePHP 构建。

我有一个对象、类型和用户模块,分别有相应的控制器和视图。

用户有 3 种类型:superuseradminuser

管理员和超级用户和 CRUD 一切,用户只能 CRUD ObjectTypologies 由他们创建,所以我有 3 个表 UserTypologyObject,其中类型和对象表包含一列user_id,这是创建它们的用户的 ID。

所以我想要检查$object['Object']['user_id']== $user['User']['id'] 是否相等,然后继续。

用户必须先登录。代码如下:

这是 AppController

    <?php

App::uses('Controller', 'Controller');
App::uses('AuthComponent', 'Controller/Component');

class AppController extends Controller {

    public $components = array(
        'DebugKit.Toolbar', 
        'Acl',
        'Session',
        'Security', 
        'Email' => array('from' =>'erland.muchasaj@atis-shpk.com', 'sendAs' => 'html'),
        'Auth'=>array(
            //'authenticate' => array('Form' => array('fields' => array('username' => 'email'))),
            'loginRedirect'=>array('controller'=>'users', 'action'=>'index'),
            'logoutRedirect'=>array('controller'=>'users', 'action'=>'index'),
            'loginError' => "Wrong Username/Password Combination",
            'authError'=>"You can't access that page",
            'authorize'=>array('Controller')
        )

    );

    public function isAuthorized($user=null) {

         if (isset($user['role']) && ($user['role'] == 'admin' || $user['role'] == 'superuser')) {
             return true;}  


       /* if ($this->action == 'delete') {
            if ($this->Auth->user('role') == 'admin') {return true; } 
            else {  return false;}
        }*/

        /* remove actions from the list of allowed actions  
    if ($this->Auth->user('role') != 'admin') { $this->Auth->deny('delete');}*/

        /*/if the prefix is setup, make sure the prefix matches their role 
         if( isset($this->params['prefix'])) 
            return (strcasecmp($this->params['prefix'],$this->Auth->user('role'))===0); 
        //shouldn't get here, better be safe than sorry 
        return false;   */

    }



    // before filter runs before any other actions is executed
    public function beforeFilter() {
        $this->Auth->allow('index');
        $this->set('logged_in', $this->Auth->loggedIn()); // we set the logged in status to the variable=> loged_in in order to catch it in our views and to use it. 
        $this->set('current_user', $this->Auth->user());  // we set the logged in user data to the variable=> current_user in order to catch it in our views and to use it.
        if (!$this->Auth->loggedIn()) {$this->Auth->authError = false;}

         //Overrides the default username and password fields used for authentication.
         //$this->Auth->fields = array('username' => 'user_username', 'password' => 'user_password');

        /*tell Auth to call the isAuthorized function before allowing access 
        $this->Auth->authorize = 'controller';
          //allow all non-logged in users access to items without a prefix 
        if( !isset($this->params['prefix'])) $this->Auth->allow('*');  */

        // for e-mail sender
         $this->Email->from = 'support@domain.com';

    }


     public function isOwnedBy($item, $user) {
          // return $item['item_user_id'] == $user['user_id']; 
          return $this->Item->field('item_user_id', array('item_user_id' => $item, 'user_id' => $user)) == $item;
       }


}

//THIS IS THE TYPOLOGY CONTROLLER

    <?php
App::uses('AppController', 'Controller');

class TypologiesController extends AppController {


    public $components = array('Paginator', 'Session'); 
    public $name = 'Typologies';



        public function isAuthorized($user) {
             // All registered users can add posts
        if ($this->action === 'add') {   return true;  }
            if ($user['role'] == 'admin' || $user['role'] == 'superuser') {return true;}
                 if (in_array($this->action, array('edit', 'delete', 'view'))) {
                    if ($user['user_id'] != $this->Typology->findByTypologyUserId($user['user_id'])) {return false;  }                
                }

        return true;
    }



/**
 * index method
 *
 * @return void
 */
    public function index() {
        $this->Typology->recursive = 0;
        $this->set('typologies', $this->Paginator->paginate());
    }

/**
 * view method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function view($id = null) {
        if (!$this->Typology->exists($id)) {
            throw new NotFoundException(__('Invalid typology'));
        }
        $options = array('conditions' => array('Typology.' . $this->Typology->primaryKey => $id));
        $this->set('typology', $this->Typology->find('first', $options));
    }

/**
 * add method
 *
 * @return void
 */
    public function add() {
        if ($this->request->is('post')) {
            $this->Typology->create();
            // ad the ID of user who has created this Object
            $this->request->data['Typology']['typology_user_id'] = $this->Auth->user('user_id'); // ad the id of user who has created this 
            if ($this->Typology->save($this->request->data)) {
                $this->Session->setFlash(__('The typology has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The typology could not be saved. Please, try again.'));
            }
        }
        $typologyItems = $this->Typology->TypologyItem->find('list');
        $typologyUsers = $this->Typology->TypologyUser->find('list');
        $this->set(compact('typologyItems', 'typologyUsers'));
    }

/**
 * edit method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function edit($id = null) {
        if (!$this->Typology->exists($id)) {
            throw new NotFoundException(__('Invalid typology'));
        }
        if ($this->request->is(array('post', 'put'))) {
            if ($this->Typology->save($this->request->data)) {
                $this->Session->setFlash(__('The typology has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The typology could not be saved. Please, try again.'));
            }
        } else {
            $options = array('conditions' => array('Typology.' . $this->Typology->primaryKey => $id));
            $this->request->data = $this->Typology->find('first', $options);
        }
        $typologyItems = $this->Typology->TypologyItem->find('list');
        $typologyUsers = $this->Typology->TypologyUser->find('list');
        $this->set(compact('typologyItems', 'typologyUsers'));
    }

/**
 * delete method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function delete($id = null) {
        $this->Typology->id = $id;
        if (!$this->Typology->exists()) {
            throw new NotFoundException(__('Invalid typology'));
        }
        $this->request->onlyAllow('post', 'delete');
        if ($this->Typology->delete()) {
            $this->Session->setFlash(__('The typology has been deleted.'));
        } else {
            $this->Session->setFlash(__('The typology could not be deleted. Please, try again.'));
        }
        return $this->redirect(array('action' => 'index'));
    }

/**
 * admin_index method
 *
 * @return void
 */
    public function admin_index() {
        $this->Typology->recursive = 0;
        $this->set('typologies', $this->Paginator->paginate());
    }

/**
 * admin_view method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function admin_view($id = null) {
        if (!$this->Typology->exists($id)) {
            throw new NotFoundException(__('Invalid typology'));
        }
        $options = array('conditions' => array('Typology.' . $this->Typology->primaryKey => $id));
        $this->set('typology', $this->Typology->find('first', $options));
    }

/**
 * admin_add method
 *
 * @return void
 */
    public function admin_add() {
        if ($this->request->is('post')) {
            $this->Typology->create();
            if ($this->Typology->save($this->request->data)) {
                $this->Session->setFlash(__('The typology has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The typology could not be saved. Please, try again.'));
            }
        }
        $typologyItems = $this->Typology->TypologyItem->find('list');
        $typologyUsers = $this->Typology->TypologyUser->find('list');
        $this->set(compact('typologyItems', 'typologyUsers'));
    }

/**
 * admin_edit method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function admin_edit($id = null) {
        if (!$this->Typology->exists($id)) {
            throw new NotFoundException(__('Invalid typology'));
        }
        if ($this->request->is(array('post', 'put'))) {
            if ($this->Typology->save($this->request->data)) {
                $this->Session->setFlash(__('The typology has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The typology could not be saved. Please, try again.'));
            }
        } else {
            $options = array('conditions' => array('Typology.' . $this->Typology->primaryKey => $id));
            $this->request->data = $this->Typology->find('first', $options);
        }
        $typologyItems = $this->Typology->TypologyItem->find('list');
        $typologyUsers = $this->Typology->TypologyUser->find('list');
        $this->set(compact('typologyItems', 'typologyUsers'));
    }

/**
 * admin_delete method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function admin_delete($id = null) {
        $this->Typology->id = $id;
        if (!$this->Typology->exists()) {
            throw new NotFoundException(__('Invalid typology'));
        }
        $this->request->onlyAllow('post', 'delete');
        if ($this->Typology->delete()) {
            $this->Session->setFlash(__('The typology has been deleted.'));
        } else {
            $this->Session->setFlash(__('The typology could not be deleted. Please, try again.'));
        }
        return $this->redirect(array('action' => 'index'));
    }}

// THIS IS USER CONTROLLER 

    <?php
App::uses('AppController', 'Controller');

class UsersController extends AppController {
    public $components = array('Paginator', 'Session');


public $name = 'Users';
    /*   // this is just for the user add controller to be allowed,
    public function beforeFilter() {
        parent::beforeFilter();
       $this->Auth->allow('add'); //over write the method of beforeFiletr only for the users
    } */

    public function isAuthorized($user) {
        if ($user['role'] == 'admin' || $user['role'] == 'superuser') {return true;}
            if (in_array($this->action, array('edit', 'delete', 'view'))) {
                if ($user['user_id'] != $this->request->params['pass'][0]) {return false;  }
           }
        return true;
    }

    public function login() {
        if(!($this->Auth->loggedIn())){
            if ($this->request->is('post')) {
                if ($this->Auth->login()) { 
                    $this->redirect($this->Auth->redirect());   
                    } else {
                        $this->Session->setFlash('Your username/password combination was incorrect');
                    }
                }
            } else {
                $this->redirect($this->Auth->redirect(array('controller' => 'users','action' => 'index'))); 
                }
    }

    public function logout() {
        $this->redirect($this->Auth->logout());
    }



/**
 * index method
 *
 * @return void
 */
    public function index() {
        $this->User->recursive = 0;
        $this->set('users', $this->Paginator->paginate());
    }

/**
 * view method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function view($id = null) {
        if (!$this->User->exists($id)) {
            throw new NotFoundException(__('Invalid user'));
        }
        $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
        $this->set('user', $this->User->find('first', $options));
    }

/**
 * add method
 *
 * @return void
 */
    public function add() {

        if ($this->request->is('post')) {
            $this->User->create();
            if ($this->User->save($this->request->data)) {
                $this->Session->setFlash(__('The user has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
            }
        }
    }

/**
 * edit method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function edit($id = null) {
        if (!$this->User->exists($id)) {
            throw new NotFoundException(__('Invalid user'));
        }
        if ($this->request->is(array('post', 'put'))) {
            if ($this->User->save($this->request->data)) {
                $this->Session->setFlash(__('The user has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
            }
        } else {
            $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
            $this->request->data = $this->User->find('first', $options);
        }
    }

/**
 * delete method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function delete($id = null) {
        $this->User->id = $id;
        if (!$this->User->exists()) {
            throw new NotFoundException(__('Invalid user'));
        }
        $this->request->onlyAllow('post', 'delete');
        if ($this->User->delete()) {
            $this->Session->setFlash(__('The user has been deleted.'));
        } else {
            $this->Session->setFlash(__('The user could not be deleted. Please, try again.'));
        }
        return $this->redirect(array('action' => 'index'));
    }

/**
 * admin_index method
 *
 * @return void
 */
    public function admin_index() {
        $this->User->recursive = 0;
        $this->set('users', $this->Paginator->paginate());
    }

/**
 * admin_view method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function admin_view($id = null) {
        if (!$this->User->exists($id)) {
            throw new NotFoundException(__('Invalid user'));
        }
        $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
        $this->set('user', $this->User->find('first', $options));
    }

/**
 * admin_add method
 *
 * @return void
 */
    public function admin_add() {
        if ($this->request->is('post')) {
            $this->User->create();
            if ($this->User->save($this->request->data)) {
                $this->Session->setFlash(__('The user has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
            }
        }
    }

/**
 * admin_edit method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function admin_edit($id = null) {
        if (!$this->User->exists($id)) {
            throw new NotFoundException(__('Invalid user'));
        }
        if ($this->request->is(array('post', 'put'))) {
            if ($this->User->save($this->request->data)) {
                $this->Session->setFlash(__('The user has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
            }
        } else {
            $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
            $this->request->data = $this->User->find('first', $options);
        }
    }

/**
 * admin_delete method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function admin_delete($id = null) {
        $this->User->id = $id;
        if (!$this->User->exists()) {
            throw new NotFoundException(__('Invalid user'));
        }
        $this->request->onlyAllow('post', 'delete');
        if ($this->User->delete()) {
            $this->Session->setFlash(__('The user has been deleted.'));
        } else {
            $this->Session->setFlash(__('The user could not be deleted. Please, try again.'));
        }
        return $this->redirect(array('action' => 'index'));
    }}

这是用户模型

<?php
App::uses('AppModel', 'Model');
/**
 * User Model
 *
 */
class User extends AppModel {
 public $name = 'User';
/**
 * Primary key field
 *
 * @var string
 */
    public $primaryKey = 'user_id';

/**
 * Display field
 *
 * @var string
 */
    public $displayField = 'user_name';

/**
 * Validation rules
 *
 * @var array
 */
    public $validate = array(
        'user_id' => array(
            'blank' => array(
                'rule' => 'blank',
                'on' => 'create',
                ),
            ),
        'user_name' => array(
            'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'User Name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 50),
                'message' => 'Name can be 50 Characters Long',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Name Can not be Empty',
            ),
        ),
        'user_surname' => array(
             'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'Surname can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 50),
                'message' => 'Surname can be 50 Characters Long',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Surname Can not be Empty',
            ),
        ),
        'user_email' => array(
            'email' => array(
                'rule' => array('email'),
                'message' => 'Enter a Valid E-mail address',

            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'E-mail can not be empty',
            ),
        ),
        'user_phone' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'message' => 'Only Numbers',
            ),
        ),
        'username' => array(
            'maxLength' => array(
                'rule' => array('maxLength' , 50),
                'message' => 'Username Can not be more then 50 characters long',

            ),
              'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'Username can only contain letters, numbers and spaces.',
            ),
              'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Username Can not be Empty',

            ),
            'isUnique' => array(
                'rule' => array('isUnique'),
                'message' => 'Username Should be Unique',
            ),
        ),
        'password' => array(
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Password Can not be Empty',

            ),
           'between'=>array(
                'rule'=>array('between', 5, 15),
                'message'=>'The password must be between 5 and 15 characters.'
            ),
           'matchPasswords'=>array(
                'rule'=>'matchPasswords',
                'message'=>'Your passwords do not match'
            ),
        ),

        'password_confirmation'=>array(
            'Not empty'=>array(
                'rule'=>'notEmpty',
                'message'=>'Please confirm your password'
            ),
         ),
        'user_role' => array(
               'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'Username can only contain letters, numbers and spaces.',
                ),
            ),
         'valid' => array(
                'rule' => array('inList', array('admin', 'moderator')),
                'message' => 'Please enter a valid role',
                'allowEmpty' => false
            )

    );




        public function matchPasswords($data) {
        if ($data['password'] == $this->data['User']['password_confirmation']) {
            return true;
        }
        $this->invalidate('password_confirmation', 'Your passwords do not match');
        return false;
    }

    public function beforeSave() {
        if (isset($this->data[$this->alias]['password'])) { //[$this->alias] is instead of ['User']
           $this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);

        }
        return true;
    }




    /**
 * hasMany associations
 *
 * @var array
 */
    public $hasMany = array(
        'UserTypologies' => array(
            'className' => 'Typology',
            'foreignKey' => 'typology_user_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
       'UserItems' => array(
            'className' => 'Item',
            'foreignKey' => 'item_user_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );



}

还有这个ISTYPOLOGY模型:

<?php
App::uses('AppModel', 'Model');
class Typology extends AppModel {
    public $primaryKey = 'typology_id';
    public $displayField = 'typology_title';


    public $validate = array(
        'typology_id' => array(
                'blank' => array(
                'rule' => 'blank',
                'on' => 'create',
            ),
        ),
        'typology_item_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'message' => 'Chose Which Object This Typology Belongs To',

            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Can Not be Empty',

            ),
        ),
        'typology_title' => array(
                'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Typology name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxlength', 50),
                'message' => 'The Typology name must not be longer than 50 characters.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Typology Title Can not be Empty',

            ),
        ),
        'typology_description1' => array(
                'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Typology name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxlength', 350),
                'message' => 'The Typology name must not be longer than 350 characters.',
            ),
        ),
        'typology_description2' => array(
                'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Typology name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxlength', 350),
                'message' => 'The Typology name must not be longer than 350 characters.',
            ),
        ),
        'typology_description3' => array(
                'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Typology name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxlength', 350),
                'message' => 'The Typology name must not be longer than 350 characters.',
            ),
        ),
        'typology_price' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'message' => 'Can Contain Only Numbers',

            ),
        ),
        'typology_category' => array(
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Chose Which Category this Typology belongs to?',

            ),
        ),
        'typology_condition' => array(
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Choose the Condition of the Typology',

            ),
        ),
        'typology_user_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'message' => 'Chose the user who created this typology',

            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                //'message' => 'Your custom message here',

            ),
        ),
    );

    //The Associations below have been created with all possible keys, those that are not needed can be removed

/**
 * belongsTo associations
 *
 * @var array
 */
    public $belongsTo = array(
        'TypologyItem' => array(
            'className' => 'Item',
            'foreignKey' => 'typology_item_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'TypologyUser' => array(
            'className' => 'User',
            'foreignKey' => 'typology_user_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

        /**
 * hasMany associations
 *
 * @var array
 */
    public $hasMany = array(
        'TypologyPhotos' => array(
            'className' => 'Photo',
            'foreignKey' => 'photo_item_typology_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );
}

解决方案是我在 Typology Controller 所做的:


public function isAuthorized($user) {
     // All registered users can add typologies
if ($this->action === 'add') {   return true;  }
    if ($user['role'] == 'admin' || $user['role'] == 'superuser') {return true;}
         if (in_array($this->action, array('edit', 'delete', 'view'))) {
    // here we grab the typology ID that we want to edit 
        $TypologyId = $this->request->params['pass'][0];
         if ($this->Typology->TypologyisOwnedBy($TypologyId, $user['user_id'])) {
                return true;
             }
        }
 return parent::isAuthorized($user);
}

在类型学模块中的功能:

    public function TypologyisOwnedBy($typology, $user) {
    return $this->field('typology_id', array('typology_id' => $typology, 'typology_user_id' => $user)) === $typology;
}

【问题讨论】:

  • 对不起,我以为我已经发布了代码。无论如何,重点是我已登录,但我想要说明的是,登录用户只能编辑他创建的类型,因为对象的逻辑是相同的,对象和类型都有一个 FK:object_user_id 和 typeology_user id 分别。 . 其中包含创建它们的用户的 id。
  • 这段代码不返回一个数组吗? $this-&gt;Typology-&gt;findByTypologyUserId($user['user_id'])
  • 我不知道它显示错误,因为你看到我想要的是比较登录的用户 ID 与 ['typology_user_id'],如果它们匹配,他可以编辑该页面,但我不知道如何?跨度>
  • 嘿伙计们,然后寻求帮助,但我设法解决了它,我会在上面发布解决方案......

标签: php mysql cakephp-2.4


【解决方案1】:

有几种内置方法可以对存储在您的应用程序中的用户进行身份验证。

FormAuthenticate allows you to authenticate users based on form POST data. Usually this is a login form that users enter information into.
BasicAuthenticate allows you to authenticate users using Basic HTTP authentication.
DigestAuthenticate allows you to authenticate users using Digest HTTP authentication.

【讨论】:

    猜你喜欢
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 2012-01-18
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多