shiro权限学习笔记
程序员文章站
2022-05-31 17:34:21
...
一、登录
1、准备加密工具类
(1)静态方法
(2)全局变量
目的:在自定义realm时可以用,而且不被修改
package cn.itsource.aisell.common;
import org.apache.shiro.crypto.hash.SimpleHash;
public class MD5Utils {
public static final String SALT = "柠檬";
public static final Integer HASHITERSTIONS = 10;
public static String getPassword(String password){
SimpleHash hash = new SimpleHash("md5", password, SALT, HASHITERSTIONS);
return hash.toHex();
}
}
2、自定义realm连接数据库验证
(1)注意:加盐需要转成ByteSource对象
ByteSource source = ByteSource.Util.bytes(MD5Utils.SALT);
(2)applicationContext-shiro.xml
<!-- 自定义的realm -->
<bean id="jdbcRealm" class="cn.itsource.aisell.shiro.JpaRealm">
<!--设置匹配器-->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="10"></property>
</bean>
</property>
</bean>
3、添加员工时给密码加密
(1)业务功能写在service层
覆写save方法,加上加密算法
@Override
public void save(Employee employee){
if (employee.getId()==null){
String password = MD5Utils.getPassword(employee.getPassword());
employee.setPassword(password);
}
employeeRepository.save(employee);
}
4、登录的两个controller
(1)跳转到登录界面controller
//与-shiro.xml中的没有登录时要跳转的界面对应 get请求
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(){
//跳转到登录界面
return "/login";
}
(2)真正做登录验证的controller
//真正的处理登录请求的界面 post请求
@RequestMapping(value = "/login",method = RequestMethod.POST)
@ResponseBody
public SuccessMsg login(String username, String password){
Subject current = SecurityUtils.getSubject();
if(!current.isAuthenticated()){
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
current.login(token);
} catch (UnknownAccountException e) {
e.printStackTrace();
return new SuccessMsg(false,"账号不存在!");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
return new SuccessMsg(false,"账号或密码错误!");
}catch (AuthenticationException e){
System.out.println("系统正在维护。。。");
return new SuccessMsg(false,"网络异常!请重试!");
}
}
return new SuccessMsg();
}
5、前台登录
(1)登录界面js
function submitForm() {
$("#loginForm").form('submit',{
url: "/login",
onSubmit: function(){
var isValid = $(this).form('validate');
if (!isValid){
$.messager.progress('close'); // 如果表单是无效的则隐藏进度条
}
return isValid; // 返回false终止表单提交
},
success: function(data){
var result =JSON.parse(data);
if (result.success){
window.location.href ="/index";
}else {
$.messager.alert('我的消息',result.msg,'error'); // 如果提交成功则隐藏进度条
}
}
});
};
(2)按Enter登录
//按键登录
$(window).keydown(function(event){
if (event.keyCode==13){
submitForm();
};
});
6、登录过期界面产生嵌套问题
(1)原因:
登录过期后,会跳转到登录界面,但是使用的是嵌套布局,所以需要判断当前登录界面是够是最顶层的窗口
//解决嵌套问题
//如果不是*父类,就跳转到*父类
if(top!=window){
top.location.href = window.location.href;
};
7、静态资源放行
(1)shiro会把所有东西过滤掉
//设置静态资源不用过滤
filterChainDefinitionMap.put("*.js", "anon");
filterChainDefinitionMap.put("*.css", "anon");
filterChainDefinitionMap.put("/images/**", "anon");
filterChainDefinitionMap.put("/layui/**", "anon");
filterChainDefinitionMap.put("/easyui/**", "anon");
filterChainDefinitionMap.put("/s/**", "anon");
8、注销
//注销登录
@RequestMapping("/logout")
public String logout(){
Subject current = SecurityUtils.getSubject();
current.logout();
return "redirect:/login";
}
二、角色与权限
1.员工-角色-权限之间的关系
(1)员工与角色————单向多对多
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "employee_role",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
(2)角色与全向————单向多对多
private String sn;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "role_permission",
joinColumns = @JoinColumn(name = "role_id"),
inverseJoinColumns = @JoinColumn(name = "permission_id")
)
2、角色中权限的展示
(1)显示全向名字
与显示图片类似
···
<th data-options="field:'permissionList',formatter:permFormat,width:100" align="center">权限</th>
···
js中
···
function permFormat(v){
//显示权限名字
var param = "";
for(let o of v){
perm +=o.name+" ";
};
return perm;
}
···
3、给角色添加权限
(1)问题1:怎么将权限全部显示出来
在dialog中用datagrid表格显示,将Permission表中所有数据加载到表格
<%--点击增加修改按钮后的弹出框--%>
<div id="editDig" class="easyui-dialog" title="role操作" style="padding:10px;width: 850px;"
data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true">
<div style="padding:10px 60px 20px 40px">
<form id="ff" class="easyui-form" method="post">
<input id="id" type="hidden" name="id" />
<table cellpadding="5">
<tr>
<td style="text-align: right">名字:</td>
<td>
<input class="easyui-validatebox" type="text" name="name"
data-options="required:true"></input>
</td>
<td style="text-align: right">编码:</td>
<td>
<input class="easyui-validatebox" type="text" name="sn"
data-options="required:true"></input>
</td>
</tr>
</table>
<div class="easyui-layout" style="width:100%;height:400px;">
<div data-options="region:'west'" style="width:50%;">
<table id="rolePermissionGrid">
<thead>
<tr>
<th data-options="field:'name',width:100">名称</th>
<th data-options="field:'sn',width:100">编码</th>
<th data-options="field:'url',width:100">资源路径</th>
</tr>
</thead>
</table>
</div>
<div data-options="region:'center'" style="width:50%">
<table id="allPermissionGrid">
<thead>
<tr>
<th data-options="field:'name',width:100">名称</th>
<th data-options="field:'sn',width:100">编码</th>
<th data-options="field:'url',width:100">资源路径</th>
</tr>
</thead>
</table>
</div>
</div>
</form>
</div>
(2)问题2:怎么从有所有权限的表中,选取权限给角色
//双击右边,左边添加数据
addPerms(index,row){
var allrows = rolePermissionGrid.datagrid('getRows');
for (let o of allrows){
if(o.id == row.id){
$.messager.show({
title:'我的消息',
msg:'已存在该权限!',
timeout:1000,
showType:'fade',
style:{
right:'',
top:document.body.scrollTop+document.documentElement.scrollTop,
bottom:''
}
});
return;
};
}
rolePermissionGrid.datagrid('appendRow',row);
},
//双击移除行
delperm(index){
rolePermissionGrid.datagrid('deleteRow',index);
}
};
rolePermissionGrid.datagrid({
fit:true,//只有充满才能显示数据
fitColumns:true,
singleSelect:true,
pagination:true,
border:false,
onDblClickRow:itsource.delperm
})
allPermissionGrid.datagrid({
fit:true,//只有充满才能显示数据
url:'/permission/pagelist',
fitColumns:true,
singleSelect:true,
pagination:true,
border:false,
onDblClickRow:itsource.addPerms
})
(3)问题3:怎么提交数据
form表单提交额外数据
onSubmit: function(param){
var roleparms = rolePermissionGrid.datagrid('getRows');
for(var i=0;i<roleparms.length;i++){
// 传递额外参数 传递到后台的参数名字:permissionList[i].id = id
param[`permissionList[${i}].id`]= roleparms[i].id;
}
//validate none 做表单字段验证,当所有字段都有效的时候返回true。该方法使用validatebox(验证框)插件。
var isValid = $(this).form('validate');
if (!isValid){
$.messager.progress('close'); // 如果表单是无效的则隐藏进度条
}
return isValid; // 返回false终止表单提交
},
4、修改权限
(1)问题:当修改权限,但是没提交就关闭修改框后,再次点击修改按钮,不能正确实现原有权限
解决方案:将原数据拷贝一份
//表单加载已选择的数据
editform.form('load',select);
//将选中的数据备份一份, 免得被污染
var copyPerms = [...select.permissionList];
//权限表格加载本地数据
rolePermissionGrid.datagrid('loadData',copyPerms);
5、修改提交
(1)问题1:当修改后的权限数量比原来的少时,会保存失败
原因:解决数据丢失的方法没有写完整
解决方案:
//解决修改时数据丢失问题,会给另一个形参加上此注解、且名字一样的,一个查询好的对象。
@ModelAttribute("editRole")
public Role lossData(Long id,String cmd){
if (id!=null&&"updata".equals(cmd)){
Role role = roleService.findOne(id);
//设置关联对象清空,解决修改的时候出错。(修改后的权限数量比原来的多)
role.getPermissionList().clear();
return role;
}
return null;
}