Shiro認證功能最簡使用

shiro做了個認證控制的demo。整個demo是基於session記錄用戶登錄狀態的。在本文中,將介紹shiro的最簡使用方法和其執行流程的簡析。

 

一、使用入門

1、在pom文件添加shiro的依賴

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

2、在web.xml中配置如下過濾器

<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、在spring配置文件shiro.xml中配置如下bean

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- 登錄url -->
    <property name="loginUrl" value="/login"/>
    <!-- 登錄成功跳轉的url -->
    <property name="successUrl" value="/home.jsp" />  
    <!-- url採用的過濾方式,anon表示不需要登錄就可以訪問的url,authc表示需要登錄纔可以訪問 -->
    <property name="filterChainDefinitions">
        <value>
           /login.jsp                  = anon
           /**                         = authc
        </value>
    </property>
</bean>

需要注意的是這裏的bean id一定要和web.xml中的filter-name一致。

4、寫一個MyAuthorizingRealm繼承AuthorizingRealm,重寫如下兩個方法

public class MyAuthorizingRealm extends AuthorizingRealm {
    //權限分配
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
        return null;
    }
    
    //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                 throws AuthenticationException {
        return null;
    }
}

第一個方法是將用戶擁有的權限封裝到AuthorizationInfo對象返回,第二個方法用於用戶身份認證,這個方法的操作一般是:

1)根據用戶名從數據庫查找用戶對象;

2)如果找不到用戶對象表示用戶不存在,直接拋出異常,表示認證失敗;

3)如果找到用戶,將用戶名和數據庫查出來的密碼封裝到一個對象返回。

例如:

public class MyAuthorizingRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
        String username = (String) principals.getPrimaryPrincipal();

        //獲取用戶的角色
        Set<String> roles = roleService.getRolesByUsername(username); 

        //獲取用戶的權限
        Set<String> permissions = permissionService.getPermsByUsername(username);
        
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(permissions);

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                 throws AuthenticationException {
        Object username = token.getPrincipal();    //獲取用戶名字
        Object password = token.getCredentials();  //獲取密碼

        if (ObjectUtils.isEmpty(username) || ObjectUtils.isEmpty(password)) {
            throw new UnknownAccountException("密碼不能爲空");
        }

        //通過用戶名從數據庫查詢出對應的用戶對象
        User user = userService.getUserByUsername((String) username);   

        //如果爲空,則表示用戶不存在,拋出異常,表示認證失敗
        if (null == user) {
            throw new UnknownAccountException("用戶不存在");
        }
         
        //如果不爲空,將數據庫的該用戶賬號密碼取出封裝到SimpleAuthenticationInfo對象中,
        //作爲標準送入接下來的步驟中和用戶輸入的賬號密碼比對,
        //其中,ByteSource.Util.bytes(username)表示MD5加密的鹽
        return new SimpleAuthenticationInfo(username, user.getPassword(), 
                   ByteSource.Util.bytes(username), getName());
    }

}

然後將這個realm配置到shiro.xml中

<bean id="myAuthorizingRealm" class="com.mytest.shiro.MyAuthorizingRealm">
    <!--密碼加密驗證方式-->
    <property name="credentialsMatcher">
        <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <property name="hashAlgorithmName" value="MD5" />
            <property name="hashIterations" value="3" />
        </bean>
    </property>
</bean>

因爲數據庫一般不會儲存明文密碼,所以需要對用戶輸入的密碼用和數據庫密碼一樣的加密方式處理之後纔可以和從simpleAuthenticationInfo對象裏面的真實數據比對。所以在這裏配置了密碼加密方式。

5、最後在shiro.xml配置SecurityManager

<!-- Shiro默認會使用Servlet容器的Session,可通過sessionMode屬性來指定使用Shiro原生Session -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myAuthorizingRealm"/>
</bean>

SecurityManager是shiro的安全中心,將自定義的realm注入到安全中心。除了realm,還可以自定義其他很多組件。

寫到這裏,shiro部分的代碼就寫完了,把完整的shiro.xml貼一遍:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login"/>
        <property name="successUrl" value="/home.jsp" />
        <property name="filterChainDefinitions">
            <value>
                /login.jsp                  = anon
                /**                         = authc
            </value>
        </property>
    </bean>

    <!-- Shiro默認會使用Servlet容器的Session,可通過sessionMode屬性來指定使用Shiro原生Session -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="warehouseAuthorizingRealm"/>
    </bean>

    <bean id="warehouseAuthorizingRealm" class="com.mytest.shiro.myAuthorizingRealm">
        <!--密碼加密驗證方式-->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5" />
                <property name="hashIterations" value="3" />
            </bean>
        </property>
    </bean>
</beans>

6、頁面準備

登錄頁面:login.jsp

<%@ page pageEncoding="UTF-8" isELIgnored="false"%>
<html>
<head>
    <title>登錄頁面</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>登錄</h1>
    <form action="login" method="post">
        <p>用戶名 : <input type="text" name="username"></p>
        <p>密碼 : <input type="password" name="password"></p>
        <p><input type="submit" value="submit"></p>
    </form>
</body>
</html>

home頁面:home.jsp

<%@ page pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

<html>
<head>
    <title>home頁面</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <div>
        <h1>home</h1>
        <p>歡迎登錄</p>
        <p><a href="<c:url value='/logout'/>">退出登錄</a></p>
    </div>
    <div>
        <!-- 這是shiro的jsp標籤,需要name熟悉裏的權限纔可以顯示標籤裏面的內容 -->
        <shiro:hasPermission name="user:create">
            <p><a href="<c:url value='/admin/emplist.jsp'/>">員工管理權限</a></p>
        </shiro:hasPermission>
    </div>
</body>
</html>

7、測試

1)數據庫植入一條用戶數據

用戶名:0001,密碼:123(手動加密後爲fe3accef6265a64b7f2805fddff85255);

2)啓動tomcat服務器,進入登錄頁面;

3)輸入錯誤的密碼,用戶名:0001,密碼:1,登錄失敗;

4)輸入正確的密碼,登錄成功。

 

二、流程簡析

未完待續

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章