springmvc+mybatis整合shiro权限
1.需要的jar包
<properties>
<shiro.version>1.3.2</shiro.version>
</properties>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</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-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
2.web.xml配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml,classpath:applicationContext-shiro.xml</param-value>
</context-param>
<!-- shiro权限配置 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.applicationContext-shiro.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<description>shiro配置</description>
<!-- 配置缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
</bean>
<bean id="ShiroRealm" class="com.dzqc.model.common.shiro.ShiroRealm">
</bean>
<bean id="defaultWebSecurityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="realm" ref="ShiroRealm"></property>
</bean>
<bean id="shiroFilter" class="com.dzqc.model.common.shiro.ShiroPermissionFactory">
<property name="securityManager" ref="defaultWebSecurityManager"></property>
<property name="loginUrl" value="/ready/tologin"></property>
<property name="successUrl" value="/ready/success"></property>
<property name="unauthorizedUrl" value="/ready/error"></property>
<property name="filters">
<map>
<entry key="roles">
<bean class="com.dzqc.model.common.shiro.CustomRolesAuthorizationFilter" />
</entry>
</map>
</property>
<property name="filterChainDefinitions">
<value>
/static/**=anon
/resources/** = anon
/index.jsp=anon
/ready/index=authc
/ready/tologin=anon
/login/login=anon
/login/relogin=anon
/login/getMenu=authc
</value>
</property>
</bean>
</beans>
4.shiro缓存配置
<?xml version="1.0" encoding="UTF-8" ?>
<ehcache>
<diskStore path="java.io.tmpdir/shiro-spring-sample"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/>
<cache name="shiro-activeSessionCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"/>
<cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"
maxElementsInMemory="100"
eternal="false"
timeToLiveSeconds="600"
overflowToDisk="false"/>
</ehcache>
5.请求的拦截和过滤
所有的请求会经过isAccessAllowed()方法进行验证,如验证通过则返回true,如没有权限返回false
package com.dzqc.model.common.shiro;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import com.alibaba.fastjson.JSONObject;
import com.dzqc.model.common.entity.ResultData;
/**
*
* @author JIAJIAJIA
* @data 2018年8月31日 下午2:56:12
* @description TODO
*/
public class CustomRolesAuthorizationFilter extends AuthorizationFilter {
/***
* 请求过滤的回调方法
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = getSubject(request, response);
if (subject.getPrincipal() == null) {
if (isAjaxRequest((HttpServletRequest)request)) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
ResultData resultData = new ResultData();
resultData.setResult(1);
resultData.setCode(401);
resultData.setMessage("登录认证失效,请重新登录!");
response.getWriter().write(JSONObject.toJSONString(resultData));
}else {
saveRequestAndRedirectToLogin(request, response);
}
} else {
String unauthorizedUrl = getUnauthorizedUrl();
if(isAjaxRequest((HttpServletRequest)request)) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
ResultData resultData = new ResultData();
resultData.setResult(2);
resultData.setCode(402);
resultData.setMessage("您没有权限执行该操作!");
response.getWriter().write(JSONObject.toJSONString(resultData));
}else {
if (StringUtils.hasText(unauthorizedUrl)) {
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
return false;
}
/**
* 请求过滤
*/
@Override
protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws Exception {
Subject subject = getSubject(req, resp);
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) { //没有角色限制,有权限访问
return true;
}
for (int i = 0; i < rolesArray.length; i++) {
if (subject.hasRole(rolesArray[i])) { //若当前用户是rolesArray中的任何一个,则有权限访问
return true;
}
}
return false;
}
public static boolean isAjaxRequest(HttpServletRequest request) {
String requestedWith = request.getHeader("x-requested-with");
if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
return true;
} else {
return false;
}
}
}
6.从数据库中加载权限
项目启动的时候会把所有的权限加载进shiro,访问的时候 进行对比有没有访问权限
package com.dzqc.model.common.shiro;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.shiro.config.Ini;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.dzqc.model.common.entity.Function;
import com.dzqc.model.common.entity.Role;
import com.dzqc.model.common.service.SysAdminService;
/***
*
* @author JIAJIAJIA
* @data 2018年8月29日 上午11:22:58
* @description TODO
*/
public class ShiroPermissionFactory extends ShiroFilterFactoryBean {
public static String definition = "";
@Autowired
private SysAdminService sysAdminService;
@Override
public void setFilterChainDefinitions(String definitions) {
definition = definitions;//记录配置的静态过滤链
LinkedHashMap<String, String> m=new LinkedHashMap<String,String>();
m.put("/index.jsp","anon");
m.put("/trans/tologin","anon");
m.put("/login","anon");
m.put("/resources/**","anon");
m.put("/relogin","anon");
List<Role> role=sysAdminService.getFilterChain();
for(Role r:role) {
for(Function f:r.getFunctionList()) {
if(m.containsKey(f.getLinkUrl())) {
String u=m.get(f.getLinkUrl());
u=u.substring(0,u.length()-1);
u+=","+r.getName()+"]";
m.put(f.getLinkUrl(),u);
}else {
m.put(f.getLinkUrl(),"roles["+r.getName()+"]");
}
}
}
m.put("/**","authc");
//加载配置默认的过滤链
Ini ini = new Ini();
ini.load(definitions);
Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
if (CollectionUtils.isEmpty(section)) {
section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
//加上数据库中过滤链
section.putAll(m);
setFilterChainDefinitionMap(section);
}
}
7.自定义登录验证
自定义验证规则,从数据库中查询,验证通过以后回调AuthorizationInfo()方法,将该用户所有的权限加入shiro,加入缓存,如果没有缓存,则每一次请求都会经过AuthorizationInfo()方法进行权限的查询和设置。
package com.dzqc.model.common.shiro;
import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.dzqc.model.common.entity.Admin;
import com.dzqc.model.common.entity.Function;
import com.dzqc.model.common.entity.Role;
import com.dzqc.model.common.service.LoginService;
/***
* @author JIAJIAJIA
* @data 2018年8月23日 上午11:26:01
* @description TODO
* 自定义登陆 realm 验证
*/
public class ShiroRealm extends AuthorizingRealm{
@Autowired
private LoginService loginService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
if(token==null) {
return null;
}
Admin admin = null;
try {
admin = loginService.selectByUsername(upToken.getUsername());
} catch (Exception e) {
e.printStackTrace();
}
if(admin==null){
throw new UnknownAccountException("用户不存在!");
}else {
if(!admin.getPassword().equals(new String(upToken.getPassword()))){
System.out.println(admin.getPassword()+":"+new String(upToken.getPassword()));
throw new LockedAccountException("密码错误");
}
}
List<Role> role=loginService.selectRoleAndFunction(admin.getId());
admin.setRoleList(role);
SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName);
info = new SimpleAuthenticationInfo(admin,admin.getPassword(),getName());
return info;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
Admin a=(Admin) principal.getPrimaryPrincipal();
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
List<String> permissions=new ArrayList<String>();
List<String> roles=new ArrayList<String>();
for(Role r:a.getRoleList()) {
roles.add(r.getName());
for(Function f:r.getFunctionList()){
permissions.add(f.getLinkUrl());
}
}
info.addRoles(roles);//设置角色
info.addStringPermissions(permissions);//设置权限
return info;
}
}