apache shiro整合spring(一)

apache shiro整合spring

maven引入jar包html

<dependency>
     <groupId>org.apache.shiro</groupId>
     <artifactId>shiro-all</artifactId>
     <version>1.2.3</version>
</dependency>

 

將shiro配置文件整合到spring體系中

 

方式一:直接在spring的配置文件中import shiro的配置文件

web.xml中配置springjava

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

 

 

在spring配置文件中引入shiro配置文件web

<import resource="applicationContext-shiro.xml"/>

 

 

方式二:直接在web.xml中配置shiro的配置文件

<!-- Spring ApplicationContext 配置文件的路徑,可以使用通配符,多個路徑用,號分隔 此參數用於後面的Spring Context Loader -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/applicationContext-shiro.xml</param-value>
</context-param>
<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

 

 

在web.xml中定義shiro的過濾器

    <!-- 這裏的filter-name 要和spring 的applicationContext-shiro.xml 裏的
org.apache.shiro.spring.web.ShiroFilterFactoryBean 的bean name 相同 -->
    <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>

 

 

1.shiro中定義的filtername bean是要被wen.xml引用的,因此這裏的filtername要和shiro中的filtername相同 
2.shiro的filter要定義在Struts2的filter以前,不然action沒法建立
算法

shiro.xml配置文件(配置校驗的策略,哪些校驗,哪些放行)

    <!-- 安全管理 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- Single realm app.  If you have multiple realms, use the 'realms' property instead. -->
        <property name="realm" ref="authRealm"/><!-- 引用自定義的realm -->
        <!-- 二級緩存 -->
        <property name="cacheManager" ref="shiroEhcacheManager"/>
    </bean>

    <!-- 自定義權限認證 -->
    <bean id="authRealm" class="com.fyh.www.shiro.AuthRealm">
<!--        <property name="userService" ref="userService"/> -->
        <!-- 自定義密碼加密算法  -->
        <property name="credentialsMatcher" ref="passwordMatcher"/>
    </bean>

    <!-- 設置密碼加密策略 md5hash -->
    <bean id="passwordMatcher" class="com.fyh.www.shiro.CustomCredentialsMatcher"/>

    <!-- 此bean要被web.xml引用,和web.xml中的filtername同名 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/index.jsp" /> <!-- 沒有認證返回地址 -->
        <property name="unauthorizedUrl" value="/index2.jsp" /> <!-- 沒有受權返回地址 -->
        <property name="filterChainDefinitions">
            <value>            <!-- **表明任意子目錄 -->
            /login/** = anon
            /user/** = authc,roles[admin]
            /test/** = authc,perms[測試用的lkkk]
            </value>
        </property>
    </bean>

    <!-- 用戶受權/認證信息Cache, 採用EhCache  緩存 -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
    </bean>

    <!-- 保證明現了Shiro內部lifecycle函數的bean執行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 生成代理,經過代理進行控制 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
    </bean>

    <!-- 安全管理器 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

 

shiro緩存(ehcache支持ehcache-shiro.xml)

Alt text

<ehcache updateCheck="false" name="shiroCache">

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />
</ehcache>

 

 

java代碼實現

 

自定義密碼認證

public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
    public boolean doCredentialsMatch(AuthenticationToken token,
            AuthenticationInfo info) {
        UsernamePasswordToken usertoken = (UsernamePasswordToken) token; 

        //注意token.getPassword()拿到的是一個char[],不能直接用toString(),它底層實現不是咱們想的直接字符串,只能強轉
        Object tokenCredentials = Encrypt.md5(String.valueOf(usertoken.getPassword()),usertoken.getUsername());  
        Object accountCredentials = getCredentials(info);  

        //將密碼加密與系統加密後的密碼校驗,內容一致就返回true,不一致就返回false  
        return equals(tokenCredentials, accountCredentials);  
    }
}

 



util中定義shiro的MD5加密方法spring

public class Encrypt {
    /*
     * 散列算法通常用於生成數據的摘要信息,是一種不可逆的算法,通常適合存儲密碼之類的數據,
     * 常見的散列算法如MD五、SHA等。通常進行散列時最好提供一個salt(鹽),好比加密密碼「admin」,
     * 產生的散列值是「21232f297a57a5a743894a0e4a801fc3」,
     * 能夠到一些md5解密網站很容易的經過散列值獲得密碼「admin」,
     * 即若是直接對密碼進行散列相對來講破解更容易,此時咱們能夠加一些只有系統知道的干擾數據,
     * 如用戶名和ID(即鹽);這樣散列的對象是「密碼+用戶名+ID」,這樣生成的散列值相對來講更難破解。
     */

    //高強度加密算法,不可逆
    public static String md5(String password, String salt){
        return new Md5Hash(password,salt,2).toString();
    }

    public static void main(String[] args) {
        System.out.println(new Md5Hash("123456","tony",2).toString());
    }


}

 

 

自定義realm AuthRealm

在認證、受權內部實現機制中都有提到,最終處理都將交給Realm進行處理。 
由於在Shiro中,最終是經過Realm來獲取應用程序中的用戶、角色及權限信息的。 
一般狀況下,在Realm中會直接從咱們的數據源中獲取Shiro須要的驗證信息。能夠說,Realm是專用於安全框架的DAO.
apache

 
public class AuthRealm extends AuthorizingRealm{
    private UserService userService;
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    //受權
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("受權");
        //獲取當前用戶
        User user = (User)principals.fromRealm(getName()).iterator().next();
        //獲得權限字符串
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        Set<Role> roles = user.getRoles();
        List<String> list = new ArrayList();
        for(Role role :roles){
            Set<Module> modules = role.getModules();
            for(Module m:modules){
                if(m.getCtype()==0){
                    //說明是主菜單
                    list.add(m.getCpermission());
                }
            }
        }

        info.addStringPermissions(list);
        return info;
    }
    //認證  登陸
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("認證");
        UsernamePasswordToken upToken = (UsernamePasswordToken)token;

        User user = userService.findUserByName(upToken.getUsername());
        if(user==null){
            return null;
        }else{
            AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
            return info;
        }

    }

}

 

 

修改傳統登陸爲shiro登陸

public class LoginAction extends BaseAction {

    private static final long serialVersionUID = 1L;

    private String username;
    private String password;

    private UserService userService;
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public String login() throws Exception {    
        /*
         * shiro登陸方式:根據用戶名獲取密碼,密碼爲null非法用戶;有密碼檢查是否用戶填寫的密碼
         * 登陸成功後無需往httpsession中存放當前用戶,這樣就跟web容器綁定,關聯太緊密;它本身建立
         * subject對象,實現本身的session。這個跟web容器脫離,實現鬆耦合。
         */

        //調用shiro判斷當前用戶是不是系統用戶
        Subject subject = SecurityUtils.getSubject();   //獲得當前用戶
        //shiro是將用戶錄入的登陸名和密碼(未加密)封裝到token對象中
        UsernamePasswordToken token = new UsernamePasswordToken(userName,password);

        try{
            subject.login(token);   //自動調用AuthRealm.doGetAuthenticationInfo

            //寫seesion,保存當前user對象
            User curUser = (User)subject.getPrincipal();            //從shiro中獲取當前用戶
            System.out.println(curUser.getDept().getDeptName());    //讓懶加載變成當即加載
            Set<Role> roles = curUser.getRoles();
            for(Role role :roles){
                Set<Module> moduless =  role.getModules();
                for(Module m :moduless)
                   System.out.println(m.getName());
            }
            session.put(SysConstant.CURRENT_USER_INFO, curUser);    //Principal 當前用戶對象
        }catch(Exception ex){
            super.put("errorInfo","用戶名密碼錯誤,請從新填寫!");
            ex.printStackTrace();

            return "login";
        }
        return SUCCESS;
    }

    public String logout(){
        session.remove(SysConstant.CURRENT_USER_INFO);      //刪除session
        return "logout";
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

 

 

頁面使用shiro標籤

<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>

        <shiro:hasPermission name="sysadmin">
        <span id="topmenu" onclick="toModule('sysadmin');">系統管理</span>
        </shiro:hasPermission>
相關文章
相關標籤/搜索