m_Orchestrate learning system---mo系统权限思考(如何实现以及注意什么)
一、总结
一句话总结:注意不同身份访问同一客户端时候的权限,比如面板显示,比如功能按钮
数据库字段可以轻松实现不同身份
注意不同身份访问同一客户端时候的权限,比如面板显示,比如功能按钮
1、小组之间互相查看作业如何实现?
通过老师端控制数据库字段(老师允许查看不同的小组的话数据库的字段为1,否则为0),
然后在学生端根据这个数据库字段显示能否查看不同组的数据的板块(字段为1就显示面板,否则不显示),
并且还要根据学生所访问的组是否是学生所属的组从而控制一些板块和按钮的显示隐藏(比如非本组成员不能添加笔记,非本组成员看不到组类聊天等等)
2、老师检查学生作业如何实现?
在老师端加一个传送门,让老师可以进入学生端,并且当学生端的登录用户的身份为老师的时候,显示查看各组数据的一个面板,老师通过在这个面板上面选择不同的组,进而查看对应组的数据
3、不同身份访问学生端的时候最需要注意的是什么?
比如一些板块的显示权限(比如小组讨论板块,老师资源板块)
一些功能按钮的权限
4、auth做了后端验证,那么auth对应的前端认证应该是怎样的?
用php很容易找到当前访问控制器和方法,做一下对比就好了
(因为后端是auth,所以前端推荐这个)
还是用auth验证后端的方法来验证前端是否显示,原理是一样的
前端的链接(url)或者导航(nav)里面我们可以设置字段,
auth权限中也可以得到允许的用户访问的那些方法的字段,
两个字段对比,如果在允许的字段组中,就显示
代码如下:
base控制器
//將當前用戶的權限列表傳遞到頁面
public function assignAuthList(){
$auth=new Auth();
$fry_base_auth_list=$auth->getAuthList_fry(session('id'),1);
$this->assign('fry_base_auth_list',$fry_base_auth_list); //將權限組號發送到頁面,如果是超級管理員,避開前端驗證
$auth_group=$auth->getGroups(session('id'));
$fry_auth_group_num=$auth_group[0]['aga_ag_id'];
$this->assign('fry_auth_group_num',$fry_auth_group_num); }
前端函数:
超级管理员避开前端验证
//前端的auth權限認證
function frontEndAuth($now_auth_field,$auth_list,$fry_auth_group_num){
//dump($auth_list);
//如果是超級管理員,直接return true
if(intval($fry_auth_group_num)==3) return true;
$now_auth_field=strtolower($now_auth_field);
foreach ($auth_list as $key=>$val){
if($now_auth_field==$val) return true;
}
return false;
}
具体使用:
style="<?php if(!frontEndAuth('personal.information/index',$fry_base_auth_list,$fry_auth_group_num)) echo 'display: none;';?>"
5、前端权限如何实现?
auth对应前端--用php很容易找到当前访问控制器和方法,做一下对比就好了
或php或js类统一控制
就是弄出当前用户的访问权限,和元素本身的权限做对比,开控制元素的显示,隐藏
//判斷當前訪問學生頁面的用戶的權限:各種管理員,老師,合作模式,本人,同班不同組
//這個可以求出按鈕現在訪問者的身份
//每個按鈕有顯示的特定身份,兩者對比即可判斷按鈕是否顯示:比如預覽頁面的返回就是老師和管理員的,比如筆記的修改頁面就是作者本人和共享模式的
控制器
//獲取當前用戶的身份:用於前端的權限:各種管理員(admin),老師(teacher),合作模式(cooperation),本人(self),同班不同組(sameClassDiffGroup)
public function assignUserStatus(){
$base_now_visit_user_info=[];
//將身份,用戶id,小組號傳遞到頁面,用js端的函數判斷
$u_status=intval(session('u_status'));
$u_id=session('id');
$group_id=0;
if($u_status==0){
$group_id=session('group_id');
}
$base_now_visit_user_info['u_status']=$u_status;
$base_now_visit_user_info['u_id']=$u_id;
$base_now_visit_user_info['group_id']=$group_id;
$student_group_cooperation_model=\app\student\model\config\BaseMethod::getConfigVal('student_group_cooperation_model');
$base_now_visit_user_info['student_group_cooperation_model']=$student_group_cooperation_model;
//dump($base_now_visit_user_info);die;
$this->assign('base_now_visit_user_info',$base_now_visit_user_info);
}
前端函数
//判斷當前訪問學生頁面的用戶的權限:各種管理員,老師,合作模式,本人,同班不同組
//這個可以求出按鈕現在訪問者的身份
//每個按鈕有顯示的特定身份,兩者對比即可判斷按鈕是否顯示:比如預覽頁面的返回就是老師和管理員的,比如筆記的修改頁面就是作者本人和共享模式的
function getUserAuth($base_now_visit_user_info,$author_id,$author_group_id){
//這個按鈕對老師是否有權限,對管理員是否有權限
if($base_now_visit_user_info['u_status']>1){
return 'fry_s_ui_admin';
}elseif ($base_now_visit_user_info['u_status']==1){
return 'fry_s_ui_teacher';
}elseif($base_now_visit_user_info['u_status']==0){
if(intval($author_group_id)==intval($base_now_visit_user_info['group_id'])){
//如果訪問者是作者本人
if(intval($author_id)==intval($base_now_visit_user_info['u_id'])){
return 'fry_s_ui_self';
}
//如果開啟了共享模式
else if(intval($base_now_visit_user_info['student_group_cooperation_model'])==1){
return 'fry_s_ui_cooperationModel';
}
}else{
//小組號不相等說明是其它組訪問
return 'fry_s_ui_otherGroup';
}
}
return 'fry_s_ui_otherGroup';
//如果u_status>1,就是管理員
//如果u_status==1,就是老師
//如果u_status==0, 判斷小組,與頁面的小組做對比
//判斷用於,與作者做對比
//判斷判斷小組號,小組號相同判斷作者號
} //判斷哪些按鈕是否顯示,$authArr為按鈕本身顯示的權限數組
function studentUIAuth($base_now_visit_user_info,$authArr,$author_id=0,$author_group_id=0){
$nowAuth=getUserAuth($base_now_visit_user_info,$author_id,$author_group_id);
foreach ($authArr as $key=>$val){
if($val==$nowAuth) return true;
}
return false;
}
使用
比如文章的修改删除
style="<?php if(!studentUiAuth($base_now_visit_user_info,['fry_s_ui_self','fry_s_ui_cooperationModel'],$vo['a_authorid'],$vo['gid'])) echo 'display: none;';?>"
比如测试提交按钮
<div class="am-form-group">
<button type="submit" style="<?php if(!studentUIAuth($base_now_visit_user_info,['fry_s_ui_self'],session('id'),session('group_id'))) echo 'display: none;';?>" class="am-btn am-btn-secondary am-radius">
{:chooseLanguage("確定","submit");}
</button>
<button type="button" onclick="javascript:history.go(-1);" style="<?php if(!studentUIAuth($base_now_visit_user_info,['fry_s_ui_admin','fry_s_ui_teacher'])) echo 'display: none;';?>" class="am-btn am-btn-secondary am-radius">
{:chooseLanguage("返回","Go back");}
</button>
</div>
7、学生端怎么添加php的验证(比如老师关闭合作模式,学生端没有更新,修改删除按钮还在)?
确定用户的行为的分类:其实合作模式针对的是学生的个人行为+学生端学生的个人行为其实就只有笔记,其它都是小组合作的行为+
其实合作模式针对的是学生的个人行为
学生端学生的个人行为其实就只有笔记,其它都是小组合作的行为
所以在笔记的修改删除里面添加权限验证代码即可:
模型代码:
//驗證是否是後端關掉合作模式,但是學生端沒有刷新造成的筆記修改
/**
* 先判斷合作模式是否開啟
* 筆記的原作者和修改筆記的作者做對比
*
*/
public static function canCooperationModelEdit($now_editer_id,$author_id){
$student_group_cooperation_model=\app\student\model\config\BaseMethod::getConfigVal('student_group_cooperation_model');
if(intval($student_group_cooperation_model)==1) return true;
else{
if(intval($now_editer_id)==intval($author_id)) return true;
else return false;
}
return false;
}
控制端代码:
//驗證是否是後端關掉合作模式,但是學生端沒有刷新造成的筆記修改
$canCooperationModelEdit=\app\student\model\note\CooperationModel::canCooperationModelEdit(session('id'),$article['a_authorid']);
if(!$canCooperationModelEdit){
$this->error('Permission denied(可能是合作模式被關閉)!!');
}
二、小组之间互相查看作业实现
1、问题需求
现在的系统需要是在老师的控制下,小组之间可以互相查看不同组的作业(比如笔记,比如图表分析,比如各个小组的演示等等)
2、解决方法
(1)、核心思路概述
通过老师端控制数据库字段(老师允许查看不同的小组的话数据库的字段为1,否则为0),
然后在学生端根据这个数据库字段显示能否查看不同组的数据的板块(字段为1就显示面板,否则不显示),
并且还要根据学生所访问的组是否是学生所属的组从而控制一些板块和按钮的显示隐藏(比如非本组成员不能添加笔记,非本组成员看不到组类聊天等等)
(2)、功能的大致截图
选on之后学生端出现可以查看其余小组作业情况的板块
点击不同组可以查看同班不同组的数据
这只是在engage板块,其它板块也是相同的效果
(3)、具体代码实现
a、数据库字段:
数据库里面存储一字段student_can_check_dif_group,老师端用个checkbox控制该字段,允许学生小组之间相互查看就是1,不允许学生小组之间相互查看就是0,
数据库字段:
b、老师端:
老师端控制该字段的前端核心代码:
<div class="am-form-group">
<label for="student_can_check_dif_group" class="am-u-sm-3 am-form-label">是否允許小組之間互相查看筆記情況:</label>
<div class="am-u-sm-9">
<p>
<input id="student_can_check_dif_group" data-size="sm" type="checkbox" {if condition="$student_can_check_dif_group eq 1"}checked{/if}>
</p>
<small class="am-text-danger">同一個班級的不同小組之間</small>
<script>
//初始化 Switch:
$(function() { $('#student_can_check_dif_group').bootstrapSwitch(); });
//開關點擊函數
$(function () {
$('#student_can_check_dif_group').on('switchChange.bootstrapSwitch', function(event, state) {
//console.log(this); // DOM element
//console.log(event); // jQuery event
console.log(state); // true | false
//這裡ajax過去就好
console.log(typeof state);
let stateVal=0;
if(state) stateVal=1;
$.get("{:url('group/canDifGroupCheckAns')}",{state:stateVal},function(data){
if(!data){
alert('Failed(操作失敗)!');
}
//alert('Ajax从服务器端返回来的值是:'+data);
});
});
});
</script> </div>
</div>
老师端控制该字段的后台(PHP)代码:
//是否允許不同小組之間互相查看
public function canDifGroupCheckAns(){
if(request()->isAjax()){
$state=input('state');
$fry_database_config=db('1config')->select(); if($state){
$fry_database_config[0]['config_val']=strval(1);
}else{
$fry_database_config[0]['config_val']=strval(0);
}
//die;
$ans=db('1config')->update($fry_database_config[0]);
if($ans===false) return false;
return true;
}
}
c、学生端:
当这个字段的值是1的时候,学生端显示可以选择小组面板(也就是一个select可以选择不同小组查看数据)
将当前访问小组和登录学生所在小组传递到页面,从而控制特定的功能,如果当前小组等于登录学生所在小组,那么显示可以修改功能的按钮,否则不显示
学生端后台核心代码
//為不同小組之間相互查看數據功能而服務:將學生所在班級的所有小組信息發送到每個頁面
public function assignClassGroup(){
//獲取登錄用戶的身份
$u_status=intval(session('u_status'));
$g_class_id=null;
//為學生的情況
if($u_status==0){
//獲取學生id
$u_id=session('id');
//通過學生的id獲取小組號,進而獲取學生的班級號
$map=null;
$map['u_id']=$u_id;
$groupClassInfo=db('user')->alias('u')->join('group g','u.u_ugid=g.gid')->where($map)->find();
$g_class_id=$groupClassInfo['g_class_id'];
//這裡還要獲取學生所在組的組號,傳遞到頁面
$base_student_gid=$groupClassInfo['gid'];
$this->assign('base_student_gid',$base_student_gid);
}else if($u_status==1){
//當身份為老師的情況
$g_class_id=$this->userInfo['u_class'];
//老師所在的組號,就設置為0好了,和所有的組都不一樣,表示不屬於當前組
$base_student_gid=0;
$this->assign('base_student_gid',$base_student_gid);
} //通過班級號獲取這個班級所有小組的信息
$map1=null;
$map1['g_class_id']=$g_class_id;
$base_class_group=db('group')->where($map1)->select(); //將班級的第一個組寫入session
if(isset($base_class_group[0]['gid'])) session('class_first_gid',$base_class_group[0]['gid']);
//dump( session('class_first_gid'));die;
$this->assign('base_class_group',$base_class_group);
}
学生端后台核心前端代码
这个是选择小组的那个面板的前端代码
<!--1、筆記部分 使用只需要注意最後那個增加筆記的按鈕-->
<div class="pet_article_like" style="{if condition='intval($fry_database_config.student_can_check_dif_group)<1'}display: none;{/if}{if condition='$Think.session.u_status>=1'}display: block;{/if}">
<div class="pet_article_like_title">
<div style="text-align: center;">
<span class="fry_language_item fry_language_hk">查看其餘小組作業情況</span><span class="fry_language_item fry_language_en">Group View</span>
</div> <!--老師開放學生查看不同小組的數據后,這裡用於顯示選擇小組來查看不同小組的筆記-->
<div class="" style="text-align: center;">
<div class="am-form-group" style="margin-bottom: 0;margin-top:20px;margin:20px auto 0 ;">
<select data-am-selected="{btnSize: 'xs'}" id="group_view_note" onchange="javascript:location.href=this.value;">
{volist name="base_class_group" id="vo"}
<option value="{:url('group.view.groupview/diffGroupView',array('gid'=>$vo['gid'],'a_jieduan_id'=>$a_jieduan_id))}" {if condition="$now_gid eq $vo.gid"}selected{/if}>{$vo.gname}</option>
{/volist}
</select>
</div>
</div>
<!--END 老師開放學生查看不同小組的數據后,這裡用於顯示選擇小組來查看不同小組的筆記-->
</div>
</div>
这是控制所查看的组非当前组的时候,一些按钮板块不显示的代码
<div style="{if condition='$base_student_gid neq $now_gid'}display: none;{/if}">
3、优缺点分析
优点:
实现非常简便
缺点:
1、不方便权限的扩展
2、只控制了前端,没有控制后端,比如在学生查看非本组数据时,添加笔记的按钮只是隐藏了,懂一些知识的还是可以弄出按钮来,虽然这个时候用户添加的数据还是添加到自己组,但是还是有查看别人数据的时候可以添加笔记的缺陷
缺点的解决:
1、缺点2的解决方法一:可以从php的层面进行按钮和板块的隐藏,那用户就不便破解了
2、缺点1和2的解决方法:在后端添加auth权限验证,缺点1和2都解决了,身份组可以分为学生,学生访客,老师等等,这样既方便权限的扩展,又方便后台功能的限制
4、常见问题
1、上述实现方法中,是怎么控制用户在访问其它组的时候,看不到其它组的一些功能(比如小组讨论),以及只能看,不能操作其它组的数据?、
是判断用户所属的组是不是访问的当前组,如果不是则控制一些板块进行隐藏,以及把功能操作按钮隐藏
<div style="{if condition='$base_student_gid neq $now_gid'}display: none;{/if}">
三、老师检查学生作业
1、问题需求
学生做好作业(比如笔记,比如所做的数据分析,比如所做的演示等等)之后,老师要方便查看学生的作业情况
2、解决方法
(1)、大致思路
在老师端加一个传送门,让老师可以进入学生端,并且当学生端的登录用户的身份为老师的时候,显示查看各组数据的一个面板,老师通过在这个面板上面选择不同的组,进而查看对应组的数据
(2)、功能截图
老师端传送门
查看各组数据的面板
选择这个面板就可以查看本班不同组的数据了
老师登录的学生端界面(和学生登录的学生端界面有些位置是不同的)
取消了一些学生特有的功能,增加了一些老师特有的功能
(3)、核心代码
老师端:
老师端代码主要就是一个跳转链接
<li class="tpl-left-nav-item">
<a href="{:url('student.go_student_ui/goStudentUi')}" class="nav-link tpl-left-nav-link-list">
<i class="am-icon-comments"></i>
<span>
<span class="fry_language_item fry_language_hk">>學生端界面</span><span class="fry_language_item fry_language_en">Student Interface</span>
</span>
</a>
</li>
中间接控制器重定向了一道
class GoStudentUi extends Base
{
public function goStudentUi(){
$this->redirect('student/index/index');
//dump(111);die;
}
}
学生端功能:
后端
在学生端的基础控制器中指定登录学生端的身份是老师身份还是学生身份,以及将班级所在小组的第一组的组号传进session,方便老师查看的时候默认选到第一组数据,不然默认数据是为空的的那组的数据,因为老师的组号为空
//為不同小組之間相互查看數據功能而服務:將學生所在班級的所有小組信息發送到每個頁面
public function assignClassGroup(){
//獲取登錄用戶的身份
$u_status=intval(session('u_status'));
$g_class_id=null;
//為學生的情況
if($u_status==0){
//獲取學生id
$u_id=session('id');
//通過學生的id獲取小組號,進而獲取學生的班級號
$map=null;
$map['u_id']=$u_id;
$groupClassInfo=db('user')->alias('u')->join('group g','u.u_ugid=g.gid')->where($map)->find();
$g_class_id=$groupClassInfo['g_class_id'];
//這裡還要獲取學生所在組的組號,傳遞到頁面
$base_student_gid=$groupClassInfo['gid'];
$this->assign('base_student_gid',$base_student_gid);
}else if($u_status==1){
//當身份為老師的情況
$g_class_id=$this->userInfo['u_class'];
//老師所在的組號,就設置為0好了,和所有的組都不一樣,表示不屬於當前組
$base_student_gid=0;
$this->assign('base_student_gid',$base_student_gid);
} //通過班級號獲取這個班級所有小組的信息
$map1=null;
$map1['g_class_id']=$g_class_id;
$base_class_group=db('group')->where($map1)->select(); //將班級的第一個組寫入session
if(isset($base_class_group[0]['gid'])) session('class_first_gid',$base_class_group[0]['gid']);
//dump( session('class_first_gid'));die;
$this->assign('base_class_group',$base_class_group);
}
前端
具体页面显示时候老师专属的功能:
<li style="{if condition="session('u_status')<1"}display: none;{/if}"><a href="{:url('teacher/index/index')}" class="iconfont pet_nav_xinxianshi "></a><span class="fry_language_item fry_language_hk">回教師端</span><span class="fry_language_item fry_language_en">Teacher UI</span></li>
页面显示时非老师功能:
<li style="{if condition="session('u_status')>=1"}display: none;{/if}"><a href="{:url('personal/index')}"
class="iconfont pet_nav_xinxianshi "></a><span class="fry_language_item fry_language_hk">個人中心</span><span class="fry_language_item fry_language_en">Personal</span></li>
3、优缺点分析
优点:
实现特别简便
缺点:
1、不便于扩展,当扩展新的身份进学生端界面的时候,要写很多if判断,容易弄混和出错
2、只控制了前端,没有对后端代码进行限制
和前面小组之间互相查看数据的缺点是一样的,解决方法也是一样的,
缺点解决方法:
用auth权限认证就可以解决上述两个缺点,此时各种不同的身份就是各种不同的权限组
4、常见问题
1、进入学生板块的身份为老师之后,学生板块的一些板块不适合老师了,老师也需要新的板块,如何实现(最主要的就是板块里面导航的变化)?
身份判断,根据进入学生板块用户的身份来控制导航中的按钮
2、老师查看本班各组数据的时候,如何让最开始现实的数据为第一组的数据?
在基础控制器中获取本班的第一组的组号,然后用session传到系统中,页面显示数据的时候就根据这个组号显示就可以了
3、老师登录的学生端和学生登录的学生端界面一样么?
不一样的,老师登录的学生端没有学生所属的一些特定功能,也会增加一些老师所有的特定功能
四、关于权限问题的进一步思考
比如现在学生端有如下几种身份的用户需要访问:学生本人,同组学生,非本组学生,老师
1、权限的后端控制
用auth权限认证,将上述四种身份弄成四个权限组,各自控制权限即可
2、权限的前端控制
方法一:
将上述四个权限组每个设置一个权限值,比如:
学生本人:100
同组学生:90
老师:80
非本组学生:70
权限值之间的间距不是1是为了便于扩展,插入新的身份
那么现在就谈具体的功能实现:
比如小组讨论功能只有学生本人能看到,那么小组讨论功能就设置为权限值>=100才可见
比如小组展示只有学生本人和同组学生能操作,那么小组展示就设置为权限值>=90才可操作
比如老师端资源只有学生本人,同组学生,老师能看到,那么就设置老师端资源为权限值>=80才可操作
方法二:
fry_admin_permission
fry_teacher_permission
加上这样的css类,然后用js统一控制是否显示
方法三:(因为后端是auth,所以前端推荐这个)
还是用auth验证后端的方法来验证前端是否显示,原理是一样的