ssm+shiro框架搭建筆記(6)
配置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配置檔案