shiro許可權架構中的認證和授權過程_許可權架構

來源:互聯網
上載者:User
</pre><pre name="code" class="html"><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager"/>        <property name="loginUrl" value="/login"/>         <property name="successUrl" value="/first" />        <property name="filters">            <util:map>                <entry key="authc" value-ref="formAuthenticationFilter"/>            </util:map>        </property>        <property name="filterChainDefinitions">            <value>            <!-- 對靜態資源不需要進行認證 -->            /images/** = anon            /js/** = anon            /styles/** = anon            <!-- 對所有url都需要進行認證 -->                /logout = logout                /** = authc            </value>        </property>    </bean>

首先看一下Shiro中的web filter過濾器:

         預設採用的認證過濾器filter是表單過濾器,預設登入的url是/login(只要沒有認證的都會跳轉到/login路徑下),輔助登入成功url是/first。


預設登入url跳轉到的頁面是login.jsp如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><%@ page contentType="text/html; charset=UTF-8"%><%@ include file="/WEB-INF/jsp/tag.jsp"%><html><head><TITLE>藥品採購平台</TITLE><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="content-type" content="text/html; charset=UTF-8"><LINK rel="stylesheet" type="text/css" href="${baseurl}styles/style.css"><LINK rel="stylesheet" type="text/css" href="${baseurl}styles/login.css"><LINK rel="stylesheet" type="text/css"href="${baseurl}js/easyui/themes/default/easyui.css"><LINK rel="stylesheet" type="text/css"href="${baseurl}js/easyui/themes/icon.css"><STYLE type="text/css">.btnalink {cursor: hand;display: block;width: 80px;height: 29px;float: left;margin: 12px 28px 12px auto;line-height: 30px;background: url('${baseurl}images/login/btnbg.jpg') no-repeat;font-size: 14px;color: #fff;font-weight: bold;text-decoration: none;}</STYLE><%@ include file="/WEB-INF/jsp/common_js.jsp"%><script type="text/javascript">//登入提示方法function loginsubmit() {$("#loginform").submit();}</SCRIPT></HEAD><BODY style="background: #f6fdff url(${baseurl}images/login/bg1.jpg) repeat-x;"><FORM id="loginform" name="loginform" action=""method="post"><DIV class="logincon"><DIV class="title"><IMG alt="" src="${baseurl}images/login/logo.png"></DIV><DIV class="cen_con"><IMG alt="" src="${baseurl}images/login/bg2.png"></DIV><DIV class="tab_con"><input type="password" style="display:none;" /><TABLE class="tab" border="0" cellSpacing="6" cellPadding="8"><TBODY><TR><TD>使用者名稱:</TD><TD colSpan="2"><input type="text" id="usercode"name="username" style="WIDTH: 130px" /></TD></TR><TR><TD>密 碼:</TD><TD><input type="password" id="pwd" name="password" style="WIDTH: 130px" /></TD></TR><%-- <TR><TD>驗證碼:</TD><TD><input id="randomcode" name="randomcode" size="8" /> <imgid="randomcode_img" src="${baseurl}validatecode.jsp" alt=""width="56" height="20" align='absMiddle' /> <ahref=javascript:randomcode_refresh()>重新整理</a></TD></TR> --%><TR><TD colSpan="2" align="center"><input type="button"class="btnalink" onclick="loginsubmit()" value="登  錄" /><input type="reset" class="btnalink" value="重  置" /></TD></TR></TBODY></TABLE></DIV></DIV></FORM></BODY></HTML>

form過濾器有個特點就是,只要是表單提交(條件:1.post   2.action路徑為"")就相當於:

Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);

他會自動到Real中的方法進行身份認證:

/** * 身份認證 */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String userName = (String) token.getPrincipal();User user = userService.findByUsername(userName);if(user == null) {//拋出使用者不存在異常throw new UnknownAccountException();//沒找到帳號}if(user.getLocked()) {//拋出使用者被鎖定異常throw new LockedAccountException(); //帳號鎖定}// 如果查詢到返回認證資訊AuthenticationInfoSimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, user.getPassword(),ByteSource.Util.bytes(user.getCredentialsSalt()),this.getName());return simpleAuthenticationInfo;}

值得注意的是SimpleAuthenticationInfo這個方法的建構函式,因為它決定了憑證認證的方式:

1.

   public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {        this.principals = new SimplePrincipalCollection(principal, realmName);        this.credentials = credentials;    }

該構造器對應的預設任憑類,什麼都不需要輸入,沒有密碼編譯演算法,沒有迭代次數,直接通過使用者名稱和密碼進行進行驗證就可以。

<bean id="userRealm" class="com.lgy.web.shiro.UserRealm">    <!-- 設定認證憑證器 -->    <!--<property name="credentialsMatcher" ref="credentialsMatcher" /> -->    </bean>


2.

  public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {        this.principals = new SimplePrincipalCollection(principal, realmName);        this.credentials = hashedCredentials;        this.credentialsSalt = credentialsSalt;    }

這個和你加密的密碼salt有關:

package com.lgy.service;import org.apache.shiro.crypto.RandomNumberGenerator;import org.apache.shiro.crypto.SecureRandomNumberGenerator;import org.apache.shiro.crypto.hash.SimpleHash;import org.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import com.lgy.model.User;@Servicepublic class PasswordHelper {    private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();    @Value("${password.algorithmName}")    private String algorithmName;    @Value("${password.hashIterations}")    private int hashIterations;    public void encryptPassword(User user) {        user.setSalt(randomNumberGenerator.nextBytes().toHex());        String newPassword = new SimpleHash(                algorithmName,           //密碼編譯演算法                user.getPassword(),      //密碼                ByteSource.Util.bytes(user.getCredentialsSalt()),  //salt鹽   username + salt                hashIterations   //迭代次數                ).toHex();        user.setPassword(newPassword);    }}

所以需要設定憑證資訊:

<!-- Realm實現 -->    <bean id="userRealm" class="com.lgy.web.shiro.UserRealm">    <!-- 設定認證憑證器 -->    <property name="credentialsMatcher" ref="credentialsMatcher" />    </bean>         <!-- 認證憑證器 -->    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">    <!-- 演算法名稱 -->    <property name="hashAlgorithmName" value="${password.algorithmName}" />    <!-- 迭代次數 -->    <property name="hashIterations" value="${password.hashIterations}" />    </bean>   

若認證通過後,它會跳轉到設定的輔助登入成功url是/first。身份認證就到這裡結束。


授權過程如下:

shiro授權有三種方式

Shiro 支援三種方式的授權:

1 編程式:通過寫if/else 授權碼塊完成:

Subject subject =SecurityUtils.getSubject();

if(subject.hasRole(“admin”)) {

//有許可權

} else {

//無許可權

}

2 註解式:通過在執行的Java方法上放置相應的註解完成:

@RequiresRoles("admin")

public void hello() {

//有許可權

}

3.JSP/GSP 標籤:在JSP/GSP 頁面通過相應的標籤完成:

<shiro:hasRolename="admin">

<!— 有許可權—>

</shiro:hasRole>

編程試的不用說了,重點說說註解方式和jsp標籤方式:

若使用SpringMVC註解試,需要在SpringMVC的設定檔中配置註解啟動:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:util="http://www.springframework.org/schema/util"       xmlns:aop="http://www.springframework.org/schema/aop"       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.xsd       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">    <aop:config proxy-target-class="true"></aop:config>    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">        <property name="securityManager" ref="securityManager"/>    </bean></beans>

在控制器中:

    @RequiresPermissions("user:create")    @RequestMapping(value = "/create", method = RequestMethod.GET)    public String showCreateForm(Model model) {        //...        return "user/edit";    }
當進入到這個Controller中的時候,會先進入realm中的:

/** * 授權認證 */@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {User user = (User) principals.getPrimaryPrincipal();SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        authorizationInfo.setRoles(userService.findRoles(user.getUsername()));        authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));return authorizationInfo;}

         許可權比較可能有如下2個:

 @RequiresPermissions("user:create")
 @RequiresRoles("admin")

1.基於角色的認證

2.基於許可權碼的認證


若使用jsp標籤進行認證:

條件:需要匯入<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

頁面中

<shiro:hasPermission name="user:update">

......
</shiro:hasPermission>

<shiro:hasRole name="">    

      ......
 </shiro:hasRole>


同上進入該頁面中時候,若出現這樣的標籤,每出現一個都會調用realm中的:

/** * 授權認證 */@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {User user = (User) principals.getPrimaryPrincipal();SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        authorizationInfo.setRoles(userService.findRoles(user.getUsername()));        authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));return authorizationInfo;}


相當於他們調用了shiro中的:

                Subject subject = SecurityUtils.getSubject();
subject.checkRole("");
subject.checkPermission("");                 


*

shiro的jsp標籤

 

Jsp頁面添加:

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

 

標籤名稱

標籤條件(均是顯示標籤內容)

<shiro:authenticated>

登入之後

<shiro:notAuthenticated>

不在登入狀態時

<shiro:guest>

使用者在沒有RememberMe時

<shiro:user>

使用者在RememberMe時

<shiro:hasAnyRoles name="abc,123" >

在有abc或者123角色時

<shiro:hasRole name="abc">

擁有角色abc

<shiro:lacksRole name="abc">

沒有角色abc

<shiro:hasPermission name="abc">

擁有許可權資源abc

<shiro:lacksPermission name="abc">

沒有abc許可權資源

<shiro:principal>

顯示使用者身份名稱

 <shiro:principalproperty="username"/>     顯示使用者身份中的屬性值   當然每次這麼做可能浪費的效能很不好,需要配置緩衝。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.