Spring整合Shiro实现认证授权
1. 添加Shiro依赖
<shiro.version>1.2.3</shiro.version>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-aspectj</artifactId>
<version>${shiro.version}</version>
</dependency>
2. web.xml添加shiro的过滤器
添加shiro过滤器,对所有访问的url或action进行认证/权限控制
//必须添加到Struts2的filter拦截器前
<!-- shiro -->
<filter>
<!-- 过滤器代理:起到转发的作用,将请求转发给spring管理的id为shiroFilter的过滤器来处理 -->
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3. applicationContext_shiro.xml
applicationContext_shiro.xml对拦截的请求进行认证与授权
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- shiro过滤器工厂bean,相当于简介加载了9个内置过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 安全管理器组件:核心组件 -->
<property name="securityManager" ref="securityManager" />
<!-- 认证相关配置:用户必须登陆才能访问资源,否则跳转到登录页面login.html -->
<property name="loginUrl" value="/login.html" />
<!-- 授权相关配置:当用户访问了没有权限的资源时,跳转到该页面error.html -->
<property name="unauthorizedUrl" value="/error.html" />
<!-- 添加各种过滤器 -->
<property name="filters">
<map>
<entry key="perms" value-ref="erpFilter"></entry>
</map>
</property>
<!-- 过滤链定义: 哪些URL需要拦截,使用哪种过滤器来拦截 -->
<property name="filterChainDefinitions">
<value>
//无需认证即可访问的资源
/error.html=anon
/login_*=anon
// 授权配置,用户拥有权限才能访问对应的资源
/goodstype.html=perms["商品类型"]
/goodstype_*=perms["商品类型"]
/goods.html=perms["商品管理"]
/goods_*=perms["商品管理"]
/store.html=perms["仓库管理"]
/store_*=perms["仓库管理"]
/dep.html=perms["部门管理"]
/dep_*=perms["部门管理"]
/emp.html=perms["员工管理"]
/emp_*=perms["员工管理"]
/orders.html=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
/orders_*=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
/orderdetail_*=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
/store_mylist=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
/supplier_list=perms["未审核订单","未确认订单","未入库订单","已入库订单","采购录入","销售订单录入","销售订单出库","已出库订单"]
/report_order.html=perms["销售统计图"]
/report_orderReport=perms["销售统计图"]
/report_trend.html=perms["销售趋势图"]
/report_orderTrend=perms["销售趋势图"]
/storedetail.html=perms["库存查询"]
/storedetail_*=perms["库存查询"]
/storedetail_*=perms["库存查询"]
/store_*=perms["库存查询"]
/goods_*=perms["库存查询"]
/storeoper_myListByPage=perms["库存查询"]
/storealert.html=perms["库存预警"]
/storedetail_sendStorealertEmail=perms["库存预警"]
/storedetail_storealert=perms["库存预警"]
/storeoper.html=perms["库存变更查询"]
/storeoper_*=perms["库存变更查询"]
/pwd.html=perms["重置密码"]
/emp_listByPage=perms["重置密码"]
/login_resetPwd=perms["重置密码"]
/role.html=perms["角色设置"]
/role_*=perms["角色设置"]
/role_menu.html=perms["角色权限设置"]
/role_*=perms["角色权限设置"]
/emp_role.html=perms["用户角色设置"]
/emp_list=perms["用户角色设置"]
/emp_readEmpRole=perms["用户角色设置"]
/emp_updateEmpRole=perms["用户角色设置"]
//必须进行认证的资源,认证必须写在授权下面
/*.html=authc
/*=authc
</value>
</property>
</bean>
<!-- shiro的核心:大脑, 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="erpFilter">
<!-- 安全管理器中使用erpRealm执行认证 -->
<property name="realm" ref="erpRealm" />
</bean>
<!-- 注册realm认证/授权:erpReam中告诉shiro用户拥有什么权限,shiro拿过来与配置进行比较 -->
<bean id="erpRealm" class="com.itdream.erp.realms.ErpRealm">
<property name="empBiz" ref="empBiz" />
<property name="menuBiz" ref="menuBiz" />
</bean>
<!-- 注册自定义权限过滤器:多个权限访问一个url资源,满足其中一个权限就可以访问 -->
<bean id="erpFilter" class="com.itdream.erp.filter.ErpAuthorizationFilter"></bean>
</beans>
4. 用户登陆认证
/**
* 用户登录
*/
public void checkUser() {
try {
// shiro来执行用户登录
// 1.创建令牌,传入用户登录账号和密码
UsernamePasswordToken token = new UsernamePasswordToken(username, pwd);
// 2. 获得主题subject
Subject subject = SecurityUtils.getSubject();
// 3. 执行登陆
subject.login(token);
WebUtils.ajaxReturn(true, "登陆成功");
} catch (AuthenticationException e) {
log.error("登录失败", e);
WebUtils.ajaxReturn(false, "登陆失败");
}
}
5. Realm:用户身份信息:权限控制及用户登录认证
告诉shiro如何判定用户是否正确以及用户拥有哪些权限
public class ErpRealm extends AuthorizingRealm {
private IEmpBiz empBiz;
private IMenuBiz menuBiz;
@Override
// 授权方法:告诉shiro当前登陆用户有哪些权限
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
// 获得当前的登陆用户
Emp emp = (Emp) paramPrincipalCollection.getPrimaryPrincipal();
List<Menu> menuList = menuBiz.getMenusByEmpuuid(emp.getUuid());
// 实例化shiro权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 告诉shiro当前登录用户有哪些权限,这些权限访问的url在配置文件applicationContext_shiro.xml中配置
for (Menu menu : menuList) {
// 添加用户拥有的菜单名作为权限配置,用户拥有该菜单名,就有访问该菜单名对应的配置的页面的访问权限(据配置而定)
info.addStringPermission(menu.getMenuname());
}
return info;
}
@Override
// 认证方法:判定用户是否正确登陆
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken)
throws AuthenticationException {
// 获取存储在token中的账号密码
UsernamePasswordToken token = (UsernamePasswordToken) paramAuthenticationToken;
String username = token.getUsername();
char[] password = token.getPassword();
String pwd = new String(password);
// 查询数据库用户是否存在
Emp emp = empBiz.findByUsernameAndPwd(username, pwd);
if (emp != null) {
// 返回认证信息
// principal:主角,就是当前用户
// credentials:证书或凭证,这里我们用的是密码
// realmName:当前realm的名称
return new SimpleAuthenticationInfo(emp, pwd, getName());
}
// 不存在直接返回null
return null;
}
public void setEmpBiz(IEmpBiz empBiz) {
this.empBiz = empBiz;
}
public void setMenuBiz(IMenuBiz menuBiz) {
this.menuBiz = menuBiz;
}
}
写完ErpRealm要去applicationContext_shiro.xml中注册,并将注入shiro核心SecurityManager,shiro在执行login时会调用这个realm进行认证以及授权
在applicationContext_shiro的过滤链配置权限控制:
告诉shiro什么资源有什么权限才可以访问
<!-- 过滤链定义: 哪些URL需要拦截,使用哪种过滤器来拦截 -->
<property name="filterChainDefinitions">
<!--可以直接放行的资源-->
/error.html=anon
/login_*=anon
<!--权限控制,拥有指定权限才能访问指定资源-->
/goodstype.html=perms["商品类型"]
/goodstype_*=perms["商品类型"]
<!--认证:未通过认证不能进行访问的资源-->
/*.html=authc
/*=authc
</property>
6. 自定义权限过滤器
权限配置完成后,会出现多个权限访问同一个url的情况,这种情况只能使用:
/orders.html=perms["未审核订单","未确认订单"]来配置,如果分开配置后面的会覆盖前面的.
但是这种写法,shiro默认是必须同时拥有两种权限定义:未审核电脑,未确认订单才能访问。
因此自定义权限过滤器覆盖默认权限过滤器,使它满足其中一个权限定义就能访问对应资源
自定义权限过滤器,继承AuthorizationFilter
/**
* 自定义权限过滤器,让满足其中一个perms就可以访问该url
*/
public class ErpAuthorizationFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
Subject subject = getSubject(request, response);
String[] perms = (String[]) mappedValue;
if (perms != null && perms.length > 0) {
if (perms.length == 1) {
if (!subject.isPermitted(perms[0])) {// 如果配置文件只设置了一个perm条件且不满足,返回false,如果没有则会出循环执行true
return false;
}
} else {
for (String perm : perms) {
if (subject.isPermitted(perm)) {// 一旦该用户权限有一个符合perms条件了,就让其通过
return true;
}
}
// 设置了权限但用户一个条件都不符合就返回false
return false;
}
}
// 如果配置文件中没有配置perms,直接返回true
return true;
}
}
applicationContext_shiro.xml注册并使用该自定义过滤器:
<!-- 注册自定义权限过滤器 -->
<bean id="erpFilter" class="com.itdream.erp.filter.ErpAuthorizationFilter"></bean>
在shiro过滤器工厂bean中添加自定义过滤器
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 添加各种过滤器 -->
<property name="filters">
<map>
<entry key="perms" value-ref="erpFilter"></entry>
</map>
</property>
</bean>
在shiro核心:securityManager的bean上添加depends-on
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="erpFilter">
<!-- 安全管理器中使用erpRealm执行认证 -->
<property name="realm" ref="erpRealm" />
</bean>
网友评论