配置shiro
(1). 使用maven导入依赖包。
<!-- shiro start --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.6.6</version> </dependency> <!-- shiro end -->
(2). 配置web.xml。
文件添加一下配置信息:
配置拦截器,拦截路径为/*<!-- shiro 安全过滤器滤器 start--> <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml --> <!-- 这个拦截器的filter-name:shiroFilter 要在spring配置文件中有配置--> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all --> <!-- requests. Usually this filter mapping is defined first (before all others) to --> <!-- ensure that Shiro works in subsequent filters in the filter chain: --> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/</url-pattern> </filter-mapping> <!-- shiro 安全过滤器滤器 end-->
(3).配置spring.xml文件。
文件添加一下配置信息:
<!-- shiro配置 --> <import resource="spring-shiro.xml"/>
(4).配置spring-mvc.xml文件。
文件添加一下配置信息:
<!-- 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions) start,需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <!-- 开启Shiro的注解end -->
(5).配置spring-shiro.xml文件。
文件配置信息:<br />
<!--
Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行
Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持
-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
<property name="loginUrl" value="/login.html"/>
<!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码) -->
<!-- <property name="successUrl" value="/" ></property> -->
<!-- 用户访问未对其授权的资源时,所显示的连接 -->
<property name="unauthorizedUrl" value="/"></property>
<property name="filterChainDefinitions">
<value>
/login.html = anon
</value>
</property>
<!-- 自定义拦截器 -->
<!-- <property name="filters">
<util:map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
</util:map>
</property> -->
</bean>
<!-- 缓存管理器 使用本地Ehcache实现 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
</bean>
<!-- 凭证匹配器 -->
<!-- <bean id="credentialsMatcher" class="com.github.zhangkaitao.shiro.chapter12.credentials.RetryLimitHashedCredentialsMatcher">
<constructor-arg ref="cacheManager"/>
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="2"/>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean> -->
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="jsid"/>
<!-- 设置Cookie名字,默认为JSESSIONID -->
<!-- <property name="name" value="" /> -->
<!-- 设置Cookie的域名,默认空,即当前访问的域名 -->
<!-- <property name="domain" value="" /> -->
<!-- 设置Cookie的路径,默认空,即存储在域名根下 -->
<!-- <property name="path" value="" /> -->
<!-- 如果设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击; 此特性需要实现了Servlet 2.5 MR6及以上版本的规范的Servlet容器支持 -->
<property name="httpOnly" value="true"/>
<!-- 设置Cookie的过期时间,秒为单位,默认-1表示关闭浏览器时过期Cookie -->
<property name="maxAge" value="-1"/>
</bean>
<!-- 会话DAO -->
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<!-- <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> -->
<!-- 会话ID生成器 -->
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 会话验证调度器 -->
<bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
<!-- 设置调度时间间隔,单位毫秒,默认就是1小时 -->
<!-- <property name="interval" value=""/> -->
<property name="sessionValidationInterval" value="1800000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 设置全局会话超时时间,默认30分钟,即如果30分钟内没有访问会话将过期-->
<property name="globalSessionTimeout" value="1800000"/>
<!-- session失效后是否删除 -->
<!-- 默认是开启的,在会话过期后会调用SessionDAO的delete方法删除会话:如会话时持久化存储的,可以调用此方法进行删除 -->
<property name="deleteInvalidSessions" value="true"/>
<!-- 是否开启会话验证器,默认是开启的 -->
<property name="sessionValidationSchedulerEnabled" value="true"/>
<!-- 设置会话验证调度器,默认就是使用 -->
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<property name="sessionDAO" ref="sessionDAO"/>
<!-- 是否启用/禁用Session Id Cookie,默认是启用的;如果禁用后将不会设置Session Id Cookie, 即默认使用了Servlet容器的JSESSIONID,且通过URL重写(URL中的“;JSESSIONID=id”部分)保存Session Id -->
<property name="sessionIdCookieEnabled" value="true"/>
<!-- 会话Cookie模板 -->
<!-- <property name="sessionIdCookie" ref="sessionIdCookie"/> -->
</bean>
<!-- 自定义Realm实现 -->
<bean id="shiroRealm" class="com.lcl.shiro.filter.realmManage"/>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroRealm"/>
<property name="sessionManager" ref="sessionManager"/>
<!-- <property name="cacheManager" ref="cacheManager"/> -->
</bean>
<!-- Shiro生命周期处理器-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
(6).配置ehcache-shiro.xml,为以后使用做准备。
文件配置信息:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">
<diskStore path="java.io.tmpdir" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="18000"
timeToLiveSeconds="18000"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
</ehcache>
(7).测试代码。
realmManage.java—登录校验类,在之前项目中 创建
package com.lcl.shiro.filter;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.lcl.sys.service.LoginService;
public class realmManage extends AuthorizingRealm implements Serializable{
/**
* Logger日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(realmManage.class);
@Autowired
private LoginService loginService;
/**
* 权限授权函数,查詢用戶的所擁有的權限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
String userName = (String) principal.getPrimaryPrincipal();
// 取得用户的所有权限
Set permissions = new HashSet();
Set roleNames = new HashSet();
//查詢用戶角色集合
List roleList = loginService.selectRolesByName(userName);
for(String role : roleList){
roleNames.add(role);
}
//查詢用戶權限集合
List permissionList = loginService.selectHasPermissionsByName(userName);
for(String permissionUnion : permissionList){
permissions.add(permissionUnion);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
info.setStringPermissions(permissions);
return info;
}
/**
* 身份认证函数
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authctoken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authctoken;
String userName = (String) token.getPrincipal(); // 得到用户名
String pwd = new String((char[]) token.getCredentials()); // 得到密码
String password =”“;
try {
password = loginService.selectPwdByName(userName);
} catch (Exception e) {
throw new ShiroException();//账号异常
}
if (password == null || “”.equals(password)) {
throw new UnknownAccountException(); //如果用户名错误
}
if(!pwd.equals(password)) {
throw new IncorrectCredentialsException(); //如果密码错误
}
//如果身份认证验证成功,返回一个AuthenticationInfo实现;
return new SimpleAuthenticationInfo(userName, pwd, getName());
}
}
LoginController.java—Controller类 在登录控制类 添加一下方法
@RequestMapping(value="login")
@ResponseBody
public Map<String, Object> login(@RequestParam("userName") String username, @RequestParam("pwd") String pwd,@RequestParam("autoLogin") String autoLogin, @RequestParam("remember") String remember){
Map<String, Object> oMap = new HashMap<String, Object>();
Map<String, Object> errorInfo = new HashMap<String, Object>();
//得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, pwd);
try {
//登录,即身份验证
if (!subject.isAuthenticated()) {//判断时候已经登录
subject.login(token);
}
//处理登录后信息保存
UserInfo userinfo = loginService.selectUserInfoByName(username);
Session session = subject.getSession();
session.setAttribute(SessionConstant.LOGIN_USER_INFO, userinfo);
LOGGER.info("账号密码登录验证------------------------success");
oMap.put("success", "success");
} catch (UnknownAccountException e) {
LOGGER.info("------------------账号不存在--------------");
errorInfo.put("userName", "账号不存在");
oMap.put("errorInfo", errorInfo);
oMap.put("success", "error");
return oMap;
} catch (IncorrectCredentialsException e) {
LOGGER.info("------------------密码错误--------------");
errorInfo.put("pwd", "密码错误");
oMap.put("errorInfo", errorInfo);
oMap.put("success", "error");
return oMap;
} catch (ShiroException e) {
LOGGER.info("------------------账号密码错误--------------");
errorInfo.put("pwd", "密码错误");
errorInfo.put("userName", "账号错误");
oMap.put("errorInfo", errorInfo);
oMap.put("success", "error");
return oMap;
}
return oMap;
}
LoginService.java—Service接口 添加一下方法
/** * * @Title: selectPwdByName * @Description: 根据用户账号查询密码 * @param username * @return String 返回类型 * @throws */ String selectPwdByName(String username); /** * * @Title: selectRolesByName * @Description: 根据用户账号查询角色集合 * @param username * @return List<String> 返回类型 * @throws */ List<String> selectRolesByName(String userName); /** * * @Title: selectPermissionsByName * @Description: 根据用户账号查询用戶權限集合标识 * @param @param userName * @return List<String> 返回类型 * @throws */ List<String> selectHasPermissionsByName(String userName); /** * * @Title: selectUserInfoByName * @Description: 根据用户名查询用户信息 * @param @param username * @return UserInfo 返回类型 * @throws */ UserInfo selectUserInfoByName(String username);
LoginServiceImp—Service接口实现类 实现以下方法
@Override
public String selectPwdByName(String userName) {
return sysManageMapper.selectPwdByName(userName);
}
@Override
public List selectRolesByName(String userName) {
return sysManageMapper.selectRolesByName(userName);
}
@Override
public List selectHasPermissionsByName(String userName) {
return sysManageMapper.selectHasPermissionsByName(userName);
}
@Override
public UserInfo selectUserInfoByName(String username) {
return sysManageMapper.selectUserInfoByName(username);
}
TestMapper.java—dao接口 添加以下DAO接口
/** * * @Title: selectPwdByName * @Description: 根据用户查询密码 * @param username * @return String 返回类型 * @throws */ String selectPwdByName(String username); /** * * @Title: selectRolesByName * @Description: 根据用户账号查询角色集合 * @param username * @return List<String> 返回类型 * @throws */ List<String> selectRolesByName(String userName); /** * * @Title: selectPermissionsByName * @Description: 根据用户账号查询用戶權限集合标识 * @param @param userName * @return List<String> 返回类型 * @throws */ List<String> selectHasPermissionsByName(String userName); /** * * @Title: selectUserInfoByName * @Description: 根据用户名查询用户 * @param @param username * @return UserInfo 返回类型 * @throws */ UserInfo selectUserInfoByName(String username);
—–实体类 只写名字。可以对照mapper.xml自己创建
—UserInfo.java
—PermissionInfo.java
—RoleInfo.java
sysManageMapper.xml—sql配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.lcl.sys.dao.SysManageMapper" > <!-- 用户信息关联表 --> <resultMap id="UserInfoBaseResultMap" type="com.lcl.sys.model.UserInfo" > <id column="id" property="id" jdbcType="VARCHAR" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="pwd" property="pwd" jdbcType="VARCHAR" /> <result column="real_name" property="realName" jdbcType="VARCHAR" /> <result column="is_delete" property="isDelete" jdbcType="CHAR" /> <result column="creater" property="creater" jdbcType="VARCHAR" /> <result column="create_time" property="createTime" jdbcType="DATE" /> <result column="updater" property="updater" jdbcType="VARCHAR" /> <result column="update_time" property="updateTime" jdbcType="DATE" /> </resultMap> <!-- 权限信息关联表 --> <resultMap id="PermissionInfoBaseResultMap" type="com.lcl.sys.model.PermissionInfo" > <id column="Id" property="id" jdbcType="VARCHAR" /> <result column="pid" property="pid" jdbcType="VARCHAR" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="url" property="url" jdbcType="VARCHAR" /> <result column="unique_name" property="unique" jdbcType="VARCHAR" /> <result column="type" property="type" jdbcType="CHAR" /> <result column="icon" property="icon" jdbcType="VARCHAR" /> <result column="is_visiable" property="isVisiable" jdbcType="CHAR" /> <result column="sort_num" property="sortNum" jdbcType="INTEGER" /> <result column="creater" property="creater" jdbcType="VARCHAR" /> <result column="create_time" property="createTime" jdbcType="DATE" /> <result column="updater" property="updater" jdbcType="VARCHAR" /> <result column="update_time" property="updateTime" jdbcType="DATE" /> <result column="isParent" property="isParent" jdbcType="BIT" /> </resultMap> <!-- 角色信息关联表 --> <resultMap id="RoleInfoBaseResultMap" type="com.lcl.sys.model.RoleInfo" > <id column="Id" property="id" jdbcType="VARCHAR" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="remark" property="remark" jdbcType="VARCHAR" /> <result column="creater" property="creater" jdbcType="VARCHAR" /> <result column="create_time" property="createTime" jdbcType="DATE" /> <result column="updater" property="updater" jdbcType="VARCHAR" /> <result column="update_time" property="updateTime" jdbcType="DATE" /> </resultMap> <!-- 根据用户查询密码 --> <select id="selectPwdByName" resultType="string" parameterType="string"> SELECT pwd FROM tb_user tu WHERE tu.name=#{username} AND tu.is_delete='0' </select> <!-- 根据用户账号查询角色集合 --> <select id="selectRolesByName" resultType="string" parameterType="string"> SELECT tr.name FROM tb_role tr WHERE tr.id IN ( SELECT tur.role_id FROM tb_user_role tur WHERE tur.id = ( SELECT id FROM TB_USER TU WHERE TU. NAME = #{username} AND tu.is_delete='0' ) ) </select> <!-- 根据用户账号查询用戶權限集合标识 --> <select id="selectHasPermissionsByName" resultType="string" parameterType="string"> SELECT tp.unique_name FROM tb_permission tp WHERE tp.Id IN ( SELECT trp.permission_id FROM tb_role_permission trp WHERE trp.role_id IN ( SELECT tr.id FROM tb_role tr WHERE tr.id IN ( SELECT tur.role_id FROM tb_user_role tur WHERE tur.id = ( SELECT id FROM TB_USER TU WHERE TU. NAME = 'admin' ) ) ) ) </select> <!-- 根据用户名查询用户 --> <select id="selectUserInfoByName" parameterType="string" resultMap="UserInfoBaseResultMap"> select tu.* from tb_user tu where tu.name = #{username} </select> </mapper>
至此,一个简单的整合完成,已经有简单的登录验证,后面会陆续加上缓存,filter。
此时项目的目录结构如下:
java文件:
--com.lcl
--base 基类包 用于存放顶层父类实现通用方法。
--constant 存放常量
--filter 放置项目filter
--shiro.filter 存放shiro有关的filter以及Realm。
--sys 业务类模块包
--controller 控制层
--dao dao层
--mapping mapper文件
--model 实体类
--service service接口
--imp service实现类
--util 工具类
--validator 校验接口存放
资源文件:
--validation 校验配置文件存放
sysValidationMessages.properties 按模块存放
config.properties 数据源配置文件
ehcache-shiro.xml 缓存配置文件
log4j.properties log4j配置文件
mybatis-interceptor.xml mybatis分页配置
spring-mvc.xml springMVC配置文件
spring-mybatis.xml mybatis配置文件
spring-service-tx.xml 事物配置文件
spring-shiro.xml shiro配置文件
spring.xml spring配置文件