TP5前后端分离RBAC权限管理API
坑神的博客文章可以参考,还可以和他交流请教,坑神人很nice!
1.后端
1.创建配置项目
1.创建项目
我用的是phpstudy和composer,在phpstudy的www目录下运行cmd,然后创建5.1的tp框架,创建名是rbac
composer create-project topthink/think=5.1.* rbac
2.设置项目
- 普通设置:
'app_debug' => true, 'app_trace'=> true
。这里我做API模块,所以方便起见可以设置默认入口文件。 - 数据库设置:database.php配置数据库信息。
- 域名设置:在phpstudy和hosts里面设置域名。
- 在项目目录下cmd:
php think make:controller api/Login
创建api模块下Login控制器。
2.管理员功能
2.1登录验证
1.首先前后端分离需要解决跨域问题,所以建一个Cross控制器,api控制器之后继承它。
php think make:controller api/Cross
<?php
namespace app\api\controller;
use think\Controller;
use think\Request;
class Cross extends Controller
{
protected function initialize()
{
parent::initialize();
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:GET, POST, OPTIONS,PUT, DELETE');
header('Access-Control-Allow-Headers:Origin,X-Requested-With,Content-Type,token,Accept,x-access-sign,x-access-time');
if (request()->isOptions()) {
exit();
}
}
}
class Login extends Cross
2.jwt(JSON Web Token)登录
首先创建model
php think make:model AdminModel
<?php
namespace app\common\model;
use think\Model;
class AdminModel extends Model
{
protected $table='admin';#表名
}
连接数据库表:在login的controller中
use app\common\model\AdminModel;
$db=new AdminModel();
引入JWT进行登录验证
composer require firebase/php-jwt
<?php
namespace app\api\controller;
use app\common\model\AdminModel;
use \Firebase\JWT\JWT;
use think\Controller;
use think\Request;
class Login extends Cross
{
public function index(Request $request)
{
$data=$request->param();
$db=new AdminModel();
$info=$db->where('username',$data['username'])->find();
if(!$info){
return json(['code' => 0, 'msg' =>'账号不存在']);
}
if($info['password']!=$data['password']){
return json(['code' => 0, 'msg' =>'账号或者密码不存在']);
}
$jwt=new JWT();
$payload=[
'iss'=>'rbac',
'aud'=>'rbac',
"iat" => time(), // token 的创建时间
"nbf" => time(), // token 的生效时间
"exp" => time() + 3600, // token 的过期时间
'aid'=>$info['id']
];
$key='key';
$keyId = "keyId";
$token=$jwt::encode($payload,$key,"HS256",$keyId);
// dump($token);
return json(['code' => 1, 'msg' =>$token]);
}
}
3.解析token
php think make:controller api/Base --plain#Base控制器只建一个初始化方法,然后这个Base类也要继承Cross实现跨域请求
这个算是一个中间件,初始化请求的token内容,从token里面获取uid信息。
<?php
namespace app\api\controller;
use think\Controller;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class Base extends Cross
{
public function initialize()
{
parent::initialize();
$header = request()->header();
if (!isset($header['token'])){
return json(['code'=>0,'msg'=>'请先登录'])->send();
}
if(empty($header['token'])){
return json(['code'=>0,'msg'=>'请先登录'])->send();
}
$key = new Key('key', 'HS256');
$info = JWT::decode($header['token'], $key);
$this->aid=$info->aid;#token验证通过,将token里的uid拿到。
// return json(['code'=>1,'token'=>$info])->send();
}
}
4.请求路由控制器继承上面的base,就可以拿到用户id,然后进行权限验证
php think make:controller api/v1/Admin
<?php
namespace app\api\controller\v1;
use app\common\model\AdminModel;
use app\api\controller\Base;
use think\Request;
class Admin extends Base
{
public function index()
{
$aid=$this->aid;
$db=new AdminModel();
$admininfo=$db->where('id',$aid)->find();#通过uid拿到这个用户的信息
dump($admininfo);die();
}
}
2.2.返回分页数据
通过$db->limit($limit)->page($page)->field($field)->select();
即可获得指定页数据。
public function index(Request $request)
{
$limit=$request->param('limit')?$request->param('limit'):10;
$page=$request->param('page')?$request->param('page'):1;
$db=new AdminModel();
$field='id,username,create_time';
$list=$db->limit($limit)->page($page)->field($field)->select();
if ($list){
$count=$db->count('id');
return json(['code'=>1,'msg'=>'获取成功','data'=>$list,'total'=>$count]);
}else{
return json(['code'=>0,'msg'=>'暂无数据']);
}
}
2.3增删改功能
public function save(Request $request)//修改和增加功能
{
$data=$request->param();
// dump($data);die();
$db=new AdminModel();
if (isset($data['id']) && !empty($data['id'])){//有id,修改功能
$info=$db->where('id',$data['id'])->find();
// dump($info);die();
if (isset($data['password'])&& !empty($data['password'])){//要修改密码
if ($info['password']===md5($data['password'])){
$data['password']=$info['password'];
}else{
$data['password']=md5($data['password']);
}
}
$res=$db->save($data,['id'=>$info['id']]);//修改对象
}else{//无id,添加功能
$data['password']=md5($data['password']);//密码加密后再存到数据库
$res=$db->save($data);//添加对象
}
if($res){
return json(['code'=>1,'msg'=>'操作成功']);
}else{
return json(['code'=>0,'msg'=>'操作失败']);
}
}
public function delete(Request $request)//删除功能
{
$id=$request->param('id');
$db=new AdminModel();
if ($id==1){//没有删除权限
return json(['code'=>0,'msg'=>'此用户不能删除']);
}
$res=$db->where('id',$id)->delete();
if ($res){
return json(['code'=>1,'msg'=>'操作成功']);
}else{
return json(['code'=>0,'msg'=>'操作失败']);
}
}
3.角色功能
1.创建模型和控制器
php think make:controller api/v1/Role
php think make:model RoleModel
2.创建数据库并在模型里连接到数据库
<?php
namespace app\common\model;
use think\Model;
class RoleModel extends Model
{
protected $table='role';
}
3.在controller里面写功能
3.1分页功能
public function index(Request $request)
{
$limit=$request->param('limit')?$request->param('limit'):10;
$page=$request->param('page')?$request->param('page'):1;
$db=new RoleModel();
$list=$db->where('status',1)->limit($limit)->page($page)->select();
if(!$list->isEmpty()){
$count=$db->where('status',1)->count('id');
return json(['code'=>1,'msg'=>'获取成功','data'=>$list,'total'=>$count]);
}else{
return json(['code'=>0,'msg'=>'暂无数据']);
}
}
3.2增删改功能
public function save(Request $request)
{
if (!$request->isPost()){
return json(['code'=>0,'msg'=>'操作失败']);
}
$data=$request->param();
$db=new RoleModel();
if(isset($data['id'])&&!empty($data['id'])){
$res=$db->save($data,['id'=>$data['id']]);
}else{
$res=$db->save($data);
}
if ($res){
return json(['code'=>1,'msg'=>'操作成功']);
}else{
return json(['code'=>0,'msg'=>'操作失败']);
}
}
public function delete(Request $request)
{
$id=$request->param('id');
$db=new RoleModel();
$res=$db->where('id',$id)->delete();
if ($res){
return json(['code'=>1,'msg'=>'操作成功']);
}else{
return json(['code'=>0,'msg'=>'操作失败']);
}
}
3.权限管理
1.创建模型和控制器
php think make:controller api/v1/Rule
php think make:model RuleModel
2.创建数据库并在模型里连接到数据库
<?php
namespace app\common\model;
use think\Model;
class RuleModel extends Model
{
protected $table='rule';
}
3.在controller里面写功能分页查询和增删改功能。
4.给管理员分配角色
1.创建模型(一对多的中间表)和控制器
php think make:controller api/v1/RoleAssign
php think make:model AdminRoleModel
<?php
namespace app\common\model;
use think\Model;
class AdminRoleModel extends Model
{
protected $table='admin_role';
}
2.在控制器里进行增改查工作。
public function save(Request $request)//增改admin的role
{
$admin_id=$request->param('admin_id');
$role_id=$request->param('role_id');
$db=new AdminRoleModel();
$info=$db->where('admin_id',$admin_id)->find();//如果admin——id存在就是修改用户角色表,否则是增加
if($info){
$res=$db->where('id',$info['id'])->setField('role_id',$role_id);
}else{
$data['admin_id']=$admin_id;
$data['role_id']=$role_id;
$res=$db->save($data);
}
if ($res){
return json(['code'=>1,'msg'=>'操作成功']);
}else{
return json(['code'=>0,'msg'=>'操作失败']);
}
}
public function read(Request $request)//根据id查看它的role有哪些
{
$admin_id=$request->param('admin_id');
$db=new AdminRoleModel();
$info=$db->where('admin_id',$admin_id)->find();
$db=new RoleModel();
$list=$db->where('status',1)->field('id,name')->select();
if($info){
$tmp=explode(',',$info['role_id']);#如果$info['role_id']的值为"1,2,3",那么$tmp的值就会是一个数组:["1", "2", "3"]
foreach($list as $k=>$v){
if(in_array($v['id'],$tmp)){
$list[$k]['check']=true;
}else{
$list[$k]['check']=false;
}
}
}else{
foreach($list as $k=>$v){
$list[$k]['check']=false;
}
}
return json(['code'=>1,'data'=>$list]);
}
5.给角色分配权限
1.创建模型(一对多的中间表)和控制器
php think make:controller api/v1/RoleRule
php think make:model RoleRuleModel
<?php
namespace app\common\model;
use think\Model;
class RoleRuleModel extends Model
{
protected $table='role_rule';
}
2.在控制器里进行增改查工作(同上)。
<?php
namespace app\api\controller\v1;
use app\common\model\RuleModel;
use app\common\model\RoleRuleModel;
use think\Controller;
use think\Request;
use app\api\controller\Base;
class RoleRule extends Base
{
public function index(Request $request)
{
$db=new RuleModel();
$list=$db->where('status',1)->field('id,name')->select();
return json(['code'=>1,'msg'=>'获取权限表','data'=>$list]);
}
public function save(Request $request)//增改role的rule
{
$role_id=$request->param('role_id');
$rule_id=$request->param('rule_id');
$db=new RoleRuleModel();
$info=$db->where('role_id',$role_id)->find();//如果role——id存在就是修改用户角色表,否则是增加
if($info){
$res=$db->where('id',$info['id'])->setField('rule_id',$rule_id);
}else{
$data['role_id']=$role_id;
$data['rule_id']=$rule_id;
$res=$db->save($data);
}
if ($res){
return json(['code'=>1,'msg'=>'操作成功']);
}else{
return json(['code'=>0,'msg'=>'操作失败']);
}
}
public function read(Request $request)//根据id查看它的role有哪些
{
$role_id=$request->param('role_id');
$db=new RoleRuleModel();
$info=$db->where('role_id',$role_id)->find();
$db=new RuleModel();
$list=$db->where('status',1)->field('id,name,pid,img,url')->select();
if($info){
$tmp=explode(',',$info['rule_id']);#如果$info['rule_id']的值为"1,2,3",那么$tmp的值就会是一个数组:["1", "2", "3"]
// dump($list);
foreach($list as $k=>$v){
if(in_array($v['id'],$tmp)){
$list[$k]['check']=true;
}else{
$list[$k]['check']=false;
}
}
}else{
foreach($list as $k=>$v){
$list[$k]['check']=false;
}
}
return json(['code'=>1,'data'=>$list]);
}
}
6.导航菜单功能(用户获取权限规则)
1.创建控制器
php think make:controller api/v1/Menu
2.在控制器里通过递归列表,拿到用户的所有权限
public function index()
{
$adminRole=new AdminRoleModel();
$role_ids=$adminRole->where('admin_id',$this->aid)->value('role_id');#通过jwt验证后拿到用户的aid,然后通过aid拿到用户的所有role_id
$role_ids_arr=explode(',',$role_ids);
$roleRule=new RoleRuleModel();
$roleRuleIds = $roleRule->whereIn('role_id', $role_ids_arr)->column('rule_id');#拿到每个role_id对应的rule_id
$tmp='';
foreach($roleRuleIds as $k=>$v){
$tmp.=','.$v;
}
$tmps=substr($tmp,1);#将用户的所有rule_id放在列表里
$rule=new RuleModel();
$fields='id,name,img,pid,url';
$list = $rule->whereIn('id', explode(',', $tmps))->field($fields)->select()->toArray();#拿到这个用户的每个rule的fileds信息
$menus=$this->buildMenuTree($list);//用递归方法遍历,将一个扁平的列表转换成树状结构时
return json(['code'=>1,'msg'=>'获取菜单成功','data'=>$menus]);
}
protected function buildMenuTree($list, $pid = 0)
{
$tree = [];
foreach ($list as $item) {
if ($item['pid'] == $pid) {
$item['children'] = $this->buildMenuTree($list, $item['id']);
$tree[] = $item;
}
}
return $tree;
}
2.前端
1.创建工程
vue create rbac_front
cd rbac_front
npm install axios
npm install element-plus
npm install vue-router
npm run serve