1. 程式人生 > >ssm+shiro框架搭建筆記(6)

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配置檔案