在第一部分,使用shiro主要做了基于url的登陆拦截,但是在真正的生产环境下往往是注解,标签等综合使用,以下是基于注解和标签的代码笔记
URL拦截权限控制是基于过滤器或者拦截器的
方法注解权限控制是基于代理(action代理)
【1】spring配置中开启shiro注解
<!-- 开启shiro注解 -->
<bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!-- 强制使用cglib为Action创建代理对象() -->
<property name="proxyTargetClass" value="true"></property>
</bean>
<!-- 切面类 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
注意:这里最好开启cglib代理(产生的是子类对象),默认是jdk代理(新的代理对象)
知识拓展:
1.JDK动态代理
此时代理对象和目标对象实现了相同的接口
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类
具体查看:http://blog.csdn.net/cpzhong/article/details/6423333
另外注意:这里如果使用shiro了,在action中的baseAction就不能直接强转了,因为如果是jdk代理是action的新代理对象,而非action对象或者子类对象,所以强转会报错,这也是为什么要使用cglib代理的原因。
【2】方法上使用权限注解
/**
* 删除派遣员
* @return
*/
@RequiresPermissions(value="staff11")//执行当前方法需要具有staff权限
//@RequiresRoles(value="staff")//执行当前方法需要具有staff角色
public String delete(){
staffService.deleteBatch(ids);
/**
* 当权限或者角色任意一个不满足都会抛出org.apache.shiro.authz.UnauthorizedException:
* 异常,所以需要我们做公共异常捕获,在struts配置文件中配置公共异常捕获页面
*/
return "list";
}
【3】Realm中授权
在bosReaml的授权方法中授予相应权限
/**
* 授权方法(这个用户有什么权限)
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("进入授权方法... ...");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("staff");//为当前用户授予staff权限
//TODO 根据当前登录用户查询数据库,获取其对应的权限数据
return info;
}
【4】访问查看
(当授权是staff11是会正常操作删除方法,当授权非staff11时,我们分别授权staff11和staff,发现staff会报错,抛出异常org.apache.shiro.authz.UnauthorizedException)
当shiro使用注解时,遇到权限和角色不足时均会抛出org.apache.shiro.authz.UnauthorizedException异常,所以这里需要捕获处理
【5】struts中配置全局异常处理
<global-results>
<result name="login">/login.jsp</result>
<result name="unauthorizedUrl">/unauthorizedUrl.jsp</result>
</global-results>
<!-- 指定全局异常捕获 -->
<!-- 当出现权限异常进行捕获,并返回至unauthorizedUrl.jsp-->
<global-exception-mappings>
<exception-mapping result="unauthorizedUrl"
exception="org.apache.shiro.authz.AuthorizationException"></exception-mapping>
</global-exception-mappings>
修改后
使用标签进行资源控制
【1】jsp页面引入shiro标签
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
【2】对需要权限拦截的菜单 按钮进行拦截添加
这里主要shiro标签可以直接包html代码,也可以直接包js代码
//工具栏(给删除安全添加权限拦截)
var toolbar = [ {
id : 'button-view',
text : '查询',
iconCls : 'icon-search',
handler : doView
}, {
id : 'button-add',
text : '增加',
iconCls : 'icon-add',
handler : doAdd
}, <shiro:hasPermission name="staff">{
id : 'button-delete',
text : '作废',
iconCls : 'icon-cancel',
handler : doDelete
},</shiro:hasPermission>{
id : 'button-save',
text : '还原',
iconCls : 'icon-save',
handler : doRestore
}];
注意:<shiro:hasPermission name="staff11">表示只有拥有staff11权限的用户才会显示该按钮
前后对比
【通过查询数据库,进行用户授权】
修改自定义Realm的授权方法
/**
* 授权方法(这个用户有什么权限)
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("进入授权方法... ...");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//info.addStringPermission("staff");//为当前用户授予staff权限
//info.addRole("staff");//为当前用户授予staff角色(角色是权限的集合)
//TODO 根据当前登录用户查询数据库,获取其对应的权限数据
//获取当前用户
User user = (User) principals.getPrimaryPrincipal();
List<Function> list = null;
if(user.getUsername().equals("admin")){
//超级管理员(查询所有权限)
list = functionDao.findAll();
}else{
//普通用户(查询拥有权限)
list = functionDao.findListByuserId(user.getId());
}
//授权
for(Function function : list){
info.addStringPermission(function.getCode());
}
return info;
}