亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Java 權限框架 Shiro 實戰二:與spring集成、filter機制

2019-11-15 00:45:31
字體:
來源:轉載
供稿:網友
java 權限框架 Shiro 實戰二:與sPRing集成、filter機制

Shiro和Spring的集成,涉及到很多相關的配置,涉及到shiro的filer機制以及它擁有的各種默認filter,涉及到shiro的權限判斷標簽,權限注解,涉及到session管理等等方面。

1. 配置

首先需要在web.xml中專門負責接入shiro的filter:

    <!-- shiro 安全過濾器 -->    <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>    <filter-mapping>        <filter-name>shiroFilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>

并且需要放在所有filter中靠前的位置,比如需要放在siteMesh的過濾器之前。

DelegatingFilterProxy 表示這是一個代理filter,它會將實際的工作,交給spring配置文件中 id="shiroFilter" 的bean來處理:

public class DelegatingFilterProxy extends GenericFilterBean {    private String contextAttribute;    private WebapplicationContext webApplicationContext;    private String targetBeanName;    private boolean targetFilterLifecycle = false;    private volatile Filter delegate;    private final Object delegateMonitor = new Object();    @Override    protected void initFilterBean() throws ServletException {        synchronized (this.delegateMonitor) {            if (this.delegate == null) {                // If no target bean name specified, use filter name.                if (this.targetBeanName == null) {                    this.targetBeanName = getFilterName();                }                // Fetch Spring root application context and initialize the delegate early,                // if possible. If the root application context will be started after this                // filter proxy, we'll have to resort to lazy initialization.                WebApplicationContext wac = findWebApplicationContext();                if (wac != null) {                    this.delegate = initDelegate(wac);                }            }        }    }
public abstract class GenericFilterBean implements        Filter, BeanNameAware, EnvironmentAware, ServletContextAware, InitializingBean, DisposableBean {    @Override    public final void init(FilterConfig filterConfig) throws ServletException {        Assert.notNull(filterConfig, "FilterConfig must not be null");        if (logger.isDebugEnabled()) {            logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");        }        this.filterConfig = filterConfig;        // Set bean properties from init parameters.        try {            PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);            BeanWrapper bw = PropertyaccessorFactory.forBeanPropertyAccess(this);            ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));            initBeanWrapper(bw);            bw.setPropertyValues(pvs, true);        }        catch (BeansException ex) {            String msg = "Failed to set bean properties on filter '" +                filterConfig.getFilterName() + "': " + ex.getMessage();            logger.error(msg, ex);            throw new NestedServletException(msg, ex);        }        // Let subclasses do whatever initialization they like.        initFilterBean();        if (logger.isDebugEnabled()) {            logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");        }    }

// Let subclasses do whatever initialization they like.

initFilterBean();

Filter 接口的 init 方法調用 initFilterBean(), 而該方法在子類中進行實現,它先獲得 this.targetBeanName = getFilterName(); bean的名稱,也就是id,然后對其進行初始化:this.delegate = initDelegate(wac); 其實就是從bean工廠中根據bean的名稱找到bean.

    protected Filter initDelegate(WebApplicationContext wac) throws ServletException {        Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);        if (isTargetFilterLifecycle()) {            delegate.init(getFilterConfig());        }        return delegate;    }

而 shiroFilter在spring中的配置如下:

    <!-- Shiro的Web過濾器 -->    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager"/>        <property name="loginUrl" value="/login"/>        <property name="successUrl" value="/"/>        <property name="unauthorizedUrl" value="/unauthorized"/>        <property name="filters">            <util:map>                <entry key="authc" value-ref="passThruAuthenticationFilter"/>            </util:map>        </property>        <property name="filterChainDefinitions">            <value>                /reg/** = anon    <!-- 注冊相關  -->                /login = authc                /logout = logout                /authenticated = authc                /loginController = anon                /js/** = anon                  /CSS/** = anon                   /img/** = anon                  /html/** = anon                /font-awesome/** = anon             <!-- /** = anon                 /user/modifyPassWord = perms["user:update", "user:select"]           -->                /** = user            </value>        </property>    </bean>

上面的shiroFilter的配置又引出了 securityManager 和 shiro 的filter機制和他自帶的一些filter.

2. securityManager 級相關配置

在上一篇文章 Java 權限框架 Shiro 實戰一:理論基礎 中我們知道securityManager是shiro的頂層對象,它管理和調用其它所有子系統,負責系統的安全。我們知道shiro有兩個類型的securityManager一個是JavaSE環境,默認是DefaultSecurityManager;一個是web環境,默認是DefaultWebSecurityManager。所以我們web環境肯定應該使用后者。我們從頂層對象一層一層向下配置。先看securityManager如何配置:

    <!-- 相當于調用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>

上面的配置相當于調用SecurityUtils.setSecurityManager(securityManager) ,來注入了下面配置的 securityManager(DefaultWebSecurityManager) :

    <!-- 安全管理器 -->    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <property name="realm" ref="userRealm"/>        <property name="cacheManager" ref="cacheManager"/>        <property name="rememberMeManager" ref="rememberMeManager"/>    </bean>

它默認使用的session管理器是 ServletContainerSessionManager,所以上面沒有配置,所以就使用默認值。配置了就會覆蓋下面的默認值:

    public DefaultWebSecurityManager() {        super();        ((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator());        this.sessionMode = HTTP_SESSION_MODE;        setSubjectFactory(new DefaultWebSubjectFactory());        setRememberMeManager(new CookieRememberMeManager());        setSessionManager(new ServletContainerSessionManager());    }

顯然 securityManager 最重要的工作就是用戶登錄認證和獲得用戶的權限等相關信息,所以 realm 是其最重要的依賴:

    <!-- Realm實現 -->    <bean id="userRealm" class="com.ems.shiro.UserRealm">        <property name="credentialsMatcher" ref="credentialsMatcher"/>        <property name="cachingEnabled" value="false"/>    </bean>

要理解上面userRealm的配置,就的先理解 UserRealm 的繼承體系:

UserRealm 繼承 AuthorizingRealm 顯然是為了獲取權限信息,對用戶進行訪問控制;繼承AuthenticatingRealm顯然是為了獲得用戶的認證信息,對用戶進行認證。而 credentialsMatcher 就是 AuthenticatingRealm 使用來進行密碼驗證的依賴的組件

public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {/**     * Credentials matcher used to determine if the provided credentials match the credentials stored in the data store.     */    private CredentialsMatcher credentialsMatcher;

再看其credentialsMatcher bean的配置:

    <!-- 憑證匹配器(驗證登錄密碼是否正確) -->    <bean id="credentialsMatcher" class="com.ems.shiro.RetryLimitHashedCredentialsMatcher">        <constructor-arg ref="cacheManager"/>        <property name="hashAlgorithmName" value="SHA-256"/>        <property name="hashIterations" value="2"/>        <property name="storedCredentialsHexEncoded" value="true"/>    </bean>

配置就是 hash加密的相關參數:hash算法,hash迭代次數等。到這里 shiro 登錄驗證的配置就完了。至于獲取用戶信息和用戶的權限的信息,都在userRealm中實現了:

public class UserRealm extends AuthorizingRealm {    @Autowired    private UserService userService;    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        String userName = (String)principals.getPrimaryPrincipal();        User user = userService.getUserByUserName (userName );        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        authorizationInfo.setRoles(userService.findRolesByUserId(user.getId()));        authorizationInfo.setStringPermissions(userService.findPermissionsByUserId(user.getId()));        return authorizationInfo;    }        @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {        String userName = (String)token.getPrincipal();        User user = userService.getUserByUserName(userName);        if(user == null) {            throw new UnknownAccountException();//沒找到賬戶        }        if(user.getLocked() == 0) {            throw new LockedAccountException(); //帳號鎖定        }        if(user.getLocked() == 2){            throw new AuthenticationException("account was inactive");        }        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(                user.getUserName(),                user.getPassword(), // 密碼                ByteSource.Util.bytes(user.getCredentialsSalt()),    // salt                getName()  // realm name        );                return authenticationInfo;    }

securityManager會在需要的時候回調上面 的 doGetAuthorizationInfo 和 doGetAuthenticationInfo 方法,從realm中獲得登錄認證信息和用戶權限信息。至于 rememberMeManager 主要是實現使用cookie表示我已經登錄過了,下次不需要重新登錄,這一個功能,也就是“記住我”登錄過這一功能:

    <!-- rememberMe管理器 -->    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">        <!-- rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位)-->        <property name="cipherKey"                  value="#{T(org.apache.shiro.codec.Base64).decode('9FvVhtFLUs0KnA3Kprsdyg==')}"/>        <property name="cookie" ref="rememberMeCookie"/>    </bean>    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">        <constructor-arg value="rememberMe"/>        <property name="httpOnly" value="true"/>        <property name="maxAge" value="2592000"/><!-- 30天 -->    </bean>

還有cacheManager的配置:

    <!--ehcache-->    <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">        <property name="configLocation" value="classpath:ehcache/ehcache.xml"/>    </bean>    <bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">        <property name="cacheManager" ref="ehcacheManager"/>    </bean>    <!-- 緩存管理器 -->    <bean id="cacheManager" class="com.ems.shiro.SpringCacheManagerWrapper">        <property name="cacheManager" ref="springCacheManager"/>    </bean>

使用的是 EhCache.

3. Shiro 的filter機制和自帶的filter

Shiro的filter是基于Servlet的Filter接口實現的。我們通過Shiro提供的form登錄filter:FormAuthenticationFilter 和 ShiroFilter 看看其實現:

繼承中的每一層都實現了一些功能:

1> NameableFilter:實現給filter取名的功能(Allows a filter to be named via JavaBeans-compatible)

/** * Allows a filter to be named via JavaBeans-compatible*/public abstract class NameableFilter extends AbstractFilter implements Nameable {    /**     * The name of this filter, unique within an application.     */    private String name;

2> OncePerRequestFilter : 保證對于同一個request,fiter只執行一次(Filter base class that guarantees to be just executed once per request)

/** * Filter base class that guarantees to be just executed once per request, * on any servlet container. It provides a {@link #doFilterInternal} * method with HttpServletRequest and HttpServletResponse arguments.*/public abstract class OncePerRequestFilter extends NameableFilter {

3> AdviceFilter: SpringMVC風格的過濾器(就是preHandle, postHandle,afterCompletion 三接口的過濾器)

 /*** A Servlet Filter that enables AOP-style &quot;around&quot; advice for a ServletRequest via * preHandle(javax.servlet.ServletRequest, javax.servlet.ServletResponse),* postHandle(javax.servlet.ServletRequest, javax.servlet.ServletResponse),* and afterCompletion(javax.servlet.ServletRequest, javax.servlet.ServletResponse, Exception)hooks.*/public abstract class AdviceFilter extends OncePerRequestFilter {    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {        return true;    }    @SuppressWarnings({"UnusedDeclaration"})    protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {    }    @SuppressWarnings({"UnusedDeclaration"})    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {    }

4> PathMatchingFilter:該過濾器僅僅處理指定的路徑(比如上面的配置:/js/** = anon,表示對 /js/ 目錄和其子目錄的請求,交給anon過濾器處理)

/** * <p>Base class for Filters that will process only specified paths and allow all others to pass through.</p>*/public abstract class PathMatchingFilter extends AdviceFilter implements PathConfigProcessor {

5> AccessControlFilter: 實現提供對資源的訪問控制,沒有權限時,重定向到登錄頁面,登錄之后跳轉到原來的那個頁面

/** * Superclass for any filter that controls access to a resource and may redirect the user to the login page * if they are not authenticated.  This superclass provides the method * saveRequestAndRedirectToLogin(javax.servlet.ServletRequest, javax.servlet.ServletResponse) * which is used by many subclasses as the behavior when a user is unauthenticated.*/public abstract class AccessControlFilter extends PathMatchingFilter {

6> AuthenticationFilter: 實現對訪問用戶的認證要求,也就是必須登錄了才能訪問

/** * Base class for all Filters that require the current user to be authenticated. This class encapsulates the * logic of checking whether a user is already authenticated in the system while subclasses are required to perform * specific logic for unauthenticated requests.*/public abstract class AuthenticationFilter extends AccessControlFilter {

7> AuthenticatingFilter: 實現判斷用戶是否有權限訪問某資源。

/** * An AuthenticationFilter that is capable of automatically performing an authentication attempt * based on the incoming request.*/public abstract class AuthenticatingFilter extends AuthenticationFilter {

8> FormAuthenticationFilter:shiro提供的用于實現用戶登錄功能,如果我們打算自己實現登錄,那么我們應用 PassThruAuthenticationFilter 來替代

/** * Requires the requesting user to be authenticated for the request to continue, and if they are not, forces the user * to login via by redirecting them to the setLoginUrl(String) you configure. * If you would prefer to handle the authentication validation and login in your own code, consider using the * PassThruAuthenticationFilter instead, which allows requests to the loginUrl to pass through to your application's code directly.*/public class FormAuthenticationFilter extends AuthenticatingFilter {

9> PassThruAuthenticationFilter : 用于我們自己在controller中實現登錄邏輯時替代FormAuthenticationFilter

/** * An authentication filter that redirects the user to the login page when they are trying to access * a protected resource. However, if the user is trying to access the login page, the filter lets * the request pass through to the application code. * The difference between this filter and the FormAuthenticationFilter is that * on a login submission (by default an HTTP POST to the login URL), the FormAuthenticationFilter filter * attempts to automatically authenticate the user by passing the username and password request parameter values to * Subject.login(AuthenticationToken) directly. * Conversely, this controller always passes all requests to the loginUrl through, both GETs and POSTs.   * This is useful in cases where the developer wants to write their own login behavior, which should include a * call to Subject.login(AuthenticationToken) at some point.  For example, if the developer has their own custom MVC  * login controller or validator, this PassThruAuthenticationFilter may be appropriate.*/public class PassThruAuthenticationFilter extends AuthenticationFilter {    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        if (isLoginRequest(request, response)) {            return true;        } else {            saveRequestAndRedirectToLogin(request, response);            return false;        }    }}

10> Shiro 自帶的filter:

Shiro自身提供了很多的默認filter 來供我們使用,主要分為兩種:一是 登錄認證相關的filter;一是權限訪問控制相關的filter;

登錄認證相關的filter有:

1)filter名稱: anon, 實現類org.apache.shiro.web.filter.authc.AnonymousFilter,主要用于靜態資源的訪問,表示無需登錄就可以訪問;

2)filter名稱: authc, 實現類org.apache.shiro.web.filter.authc.FormAuthenticationFilter,主要用于表單登錄,沒有登錄則跳轉登錄url;

3)filter名稱: user, 實現類org.apache.shiro.web.filter.authc.UserFilter,主要用于要求用戶已經登錄或者通過“記住我”功能登錄了也行。

4)filter名稱: logout, 實現類org.apache.shiro.web.filter.authc.LogoutFilter,主要用于用戶登出

5)filter名稱:authcBasic,authc的簡化形式,略。

權限訪問控制相關的filter有:

1)filter名稱: roles, 實現類org.apache.shiro.web.filter.authc.RolesAuthorizationFilter,主要用于驗證用戶必須擁有某角色,才能繼續訪問;

2)filter名稱: perms, 實現類org.apache.shiro.web.filter.authc.PermissionsAuthorizationFilter,主要用于驗證用戶必須擁有某權限,才能繼續訪問;

3)filter名稱: ssl, 實現類org.apache.shiro.web.filter.authc.SslFilter,主要用于要求訪問協議是https才能訪問,不然跳轉到https的443短褲;

4)filter名稱: port rest noSessionCreation,略。

我們上面的shiroFilter的配置中,已經使用過了上面這些自帶的filter:

                /reg/** = anon    <!-- 注冊相關  -->                /login = authc                /logout = logout                /authenticated = authc                /loginController = anon                /js/** = anon                  /css/** = anon                   /img/** = anon                  /html/** = anon                /font-awesome/** = anon                  /** = user

我們看到 /reg/** 注冊相關的,/js/**靜態資源都是使用的 anon匿名過濾器,不要求用戶已經登錄就可以訪問。

/** = user 放在最后是要求除了上面那些 url 之外的訪問路徑,都需要登錄認證過或者通過記住我登錄認證過。因為路徑比較是從上面開始列出來的先開始比較的,匹配了就走該過濾器,不會繼續下面的過濾器了。

4. shiro的權限標簽

Shiro提供了相應的權限標簽,用來實現根據用戶的角色和權限來顯示它相應的菜單和按鈕。首先需要導入shiro標簽庫:

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

標簽庫的定義位于:shiro-web.jar 包中的META-INF/shiro.tld文件中:

<?xml version="1.0" encoding="ISO-8859-1" ?><!--  ~ Licensed to the Apache Software Foundation (ASF) under one  ~ or more contributor license agreements.  See the NOTICE file  ~ distributed with this work for additional information  ~ regarding copyright ownership.  The ASF licenses this file  ~ to you under the Apache License, Version 2.0 (the  ~ "License"); you may not use this file except in compliance  ~ with the License.  You may obtain a copy of the License at  ~  ~     http://www.apache.org/licenses/LICENSE-2.0  ~  ~ Unless required by applicable law or agreed to in writing,  ~ software distributed under the License is distributed on an  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY  ~ KIND, either express or implied.  See the License for the  ~ specific language governing permissions and limitations  ~ under the License.  --><!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD jsp Tag Library 1.2//EN"  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"><taglib>  <tlib-version>1.1.2</tlib-version>  <jsp-version>1.2</jsp-version>  <short-name>Apache Shiro</short-name>  <uri>http://shiro.apache.org/tags</uri>  <description>Apache Shiro JSP Tag Library.</description>  <tag>    <name>haspermission</name>    <tag-class>org.apache.shiro.web.tags.HasPermissionTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current Subject (user)      'has' (implies) the specified permission (i.e the user has the specified ability).    </description>    <attribute>      <name>name</name>      <required>true</required>      <rtexprvalue>true</rtexprvalue>    </attribute>  </tag>  <tag>    <name>lacksPermission</name>    <tag-class>org.apache.shiro.web.tags.LacksPermissionTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current Subject (user) does      NOT have (not imply) the specified permission (i.e. the user lacks the specified ability)    </description>    <attribute>      <name>name</name>      <required>true</required>      <rtexprvalue>true</rtexprvalue>    </attribute>  </tag>  <tag>    <name>hasRole</name>    <tag-class>org.apache.shiro.web.tags.HasRoleTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current user has the specified role.</description>    <attribute>      <name>name</name>      <required>true</required>      <rtexprvalue>true</rtexprvalue>    </attribute>  </tag>  <tag>    <name>hasAnyRoles</name>    <tag-class>org.apache.shiro.web.tags.HasAnyRolesTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current user has one of the specified roles from a      comma-separated list of role names.    </description>    <attribute>      <name>name</name>      <required>true</required>      <rtexprvalue>true</rtexprvalue>    </attribute>  </tag>  <tag>    <name>lacksRole</name>    <tag-class>org.apache.shiro.web.tags.LacksRoleTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current user does NOT have the specified role      (i.e. they explicitly lack the specified role)    </description>    <attribute>      <name>name</name>      <required>true</required>      <rtexprvalue>true</rtexprvalue>    </attribute>  </tag>  <tag>    <name>authenticated</name>    <tag-class>org.apache.shiro.web.tags.AuthenticatedTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current user has successfully authenticated      _during their current session_. It is more restrictive than the 'user' tag.      It is logically opposite to the 'notAuthenticated' tag.    </description>  </tag>  <tag>    <name>notAuthenticated</name>    <tag-class>org.apache.shiro.web.tags.NotAuthenticatedTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current user has NOT succesfully authenticated      _during their current session_. It is logically opposite to the 'authenticated' tag.    </description>  </tag>  <tag>    <name>user</name>    <tag-class>org.apache.shiro.web.tags.UserTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current Subject has a known identity, either      from a previous login or from 'RememberMe' services. Note that this is semantically different      from the 'authenticated' tag, which is more restrictive. It is logically      opposite to the 'guest' tag.    </description>  </tag>  <tag>    <name>guest</name>    <tag-class>org.apache.shiro.web.tags.GuestTag</tag-class>    <body-content>JSP</body-content>    <description>Displays body content only if the current Subject IS NOT known to the system, either      because they have not logged in or they have no corresponding 'RememberMe' identity. It is logically      opposite to the 'user' tag.    </description>  </tag>  <tag>    <name>principal</name>    <tag-class>org.apache.shiro.web.tags.PrincipalTag</tag-class>    <body-content>JSP</body-content>    <description>Displays the user's principal or a property of the user's principal.</description>    <attribute>      <name>type</name>      <required>false</required>      <rtexprvalue>true</rtexprvalue>    </attribute>    <attribute>      <name>property</name>      <required>false</required>      <rtexprvalue>true</rtexprvalue>    </attribute>    <attribute>      <name>defaultValue</name>      <required>false</required>      <rtexprvalue>true</rtexprvalue>    </attribute>  </tag></taglib>
shiro.tld

其中最重要的標簽是關于角色和權限的:

<shiro:hasAnyRoles name="student,teacher"></shiro:hasAnyRoles>

<shiro:hasPermission name="user:delete"></shiro:hashPermission>

其它還有關于登錄與否的標簽:

<shiro:guest></shiro:guest> 未登錄可以顯示的信息;

<shiro:user></shiro:user> 用戶已經登錄或者通過記住我登錄后顯示的信息;

<shiro:authenticated></shiro:authenticated> 必須是實際登錄,不是通過記住我登錄的

其它標簽參考 shiro.tld文件。

shiro標簽使用示例:

<!--sidebar-menu--><div id="sidebar"><a href="Javascript:;" class="visible-phone"><i class="icon icon-home"></i> Dashboard</a>  <ul>  <shiro:hasAnyRoles name="student,teacher">      <li id="li_queryScore"><a href="${ctx}/user/queryScore"><i class="icon icon-home"></i><span>查詢成績</span></a></li>  </shiro:hasAnyRoles>  <shiro:hasAnyRoles name="teacher,admin">      <li id="li_showStudentInfo"><a href="${ctx}/student/showStudentInfo"><i class="icon icon-home"></i><span>查詢學生信息</span></a></li>  </shiro:hasAnyRoles>  <shiro:hasAnyRoles name="admin">    <li id="li_showTeacherInfo"><a href="${ctx}/teacher/showTeacherInfo"><i class="icon icon-home"></i><span>查詢教師信息</span></a></li>  </shiro:hasAnyRoles>   <shiro:hasAnyRoles name="admin">    <li id="li_getStatistic"><a href="${ctx}/statistics/getStatistic"><i class="icon icon-th"></i><span>統計</span></a></li>  </shiro:hasAnyRoles>      <shiro:hasAnyRoles name="student,teacher,admin">    <li id="li_password"><a href="${ctx}/user/password"><i class="icon icon-inbox"></i><span>密碼修改</span></a></li>  </shiro:hasAnyRoles>    <shiro:hasRole name="admin">      <li id="li_showPrivilege"><a href="${ctx}/priv/showPrivilege"><i class="icon icon-fullscreen"></i><span>權限設置</span></a></li>  </shiro:hasRole>  <shiro:hasAnyRoles name="teacher">      <li id="li_scoreRatio"><a href="${ctx}/set/scoreRatio"><i class="icon icon-tint"></i><span>成績比例設置</span></a></li>  </shiro:hasAnyRoles>   <shiro:hasAnyRoles name="admin">      <li id="li_getSetting"><a href="${ctx}/set/getSetting"><i class="icon icon-tint"></i><span>成績錄入時間設置</span></a></li>  </shiro:hasAnyRoles>   <shiro:hasAnyRoles name="student,teacher">      <li id="li_queryReExam"><a href="${ctx}/user/queryReExam"><i class="icon icon-pencil"></i><span>補考名單</span></a></li>    <li id="li_queryReLearn"><a href="${ctx}/user/queryReLearn"><i class="icon icon-pencil"></i><span>重修名單</span></a></li>  </shiro:hasAnyRoles>    </ul></div><!--sidebar-menu-->
View Code

效果是根據用戶擁有的角色,來顯示左側有哪些菜單項。

5. shiro 權限注解的使用

shiro對權限的控制,除了前面給出的在 shiroFilter這個bean中配置的過濾器:

<property name="filterChainDefinitions">            <value>                /reg/** = anon    <!-- 注冊相關  -->                /login = authc                /logout = logout                /loginController = anon                /js/** = anon                  /css/** = anon                   /img/** = anon                  /html/** = anon                /font-awesome/** = anon                  /** = user            </value>        </property>

之外,最重要的就是使用注解的方式來進行訪問控制的實現了。shiro權限注解可以達到方法級別的細膩控制,可以控制具有某些權限或者某些角色的用戶才能訪問某個方法(某個url)。先要開啟shiro權限注解功能,開啟方法參見文檔:http://shiro.apache.org/spring.html

Here is how to enable these annotations. Just add these two bean definitions to applicationContext.xml:

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- Enable Shiro Annotations for Spring-configured beans.  Only run after --><!-- the lifecycleBeanProcessor has run: --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">    <property name="securityManager" ref="securityManager"/></bean>

開啟shiro權限注解的方法二

    <aop:config />    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">        <property name="securityManager" ref="securityManager"/>    </bean>

<aop:config /> 表示開啟spring注解,而 DefaultAdvisorAutoProxyCreator 表示會自動創建代理。但是二者最好不要同時使用。

AuthorizationAttributeSourceAdvisor 通過其依賴的 securityManager 來獲取用戶的角色和權限信息,進而可以進行權限判斷。

支持的shiro注解有:

@SuppressWarnings({"unchecked"})public class AuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {    private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =            new Class[] {                    RequiresPermissions.class, RequiresRoles.class,                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class            };    protected SecurityManager securityManager = null; public AuthorizationAttributeSourceAdvisor() { setAdvice(new AopAllianceAnnotationsAuthorizingMeth
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
中文字幕欧美专区| 欧美精品制服第一页| 国产精品高潮呻吟久久av野狼| 欧美激情按摩在线| 国产色婷婷国产综合在线理论片a| 国产日韩在线看片| 久久人人爽人人爽人人片av高请| 亚洲欧美日韩一区二区在线| 欧美中在线观看| 国产在线精品自拍| 亚洲女人天堂色在线7777| 色悠悠久久88| 国产日韩精品视频| 精品福利视频导航| 欧美精品videosex性欧美| 国产欧美亚洲精品| 亲爱的老师9免费观看全集电视剧| 日韩电影大片中文字幕| 国产精品免费网站| 亚洲跨种族黑人xxx| 国产精品av电影| 国产精品综合不卡av| 欧美激情乱人伦一区| 亚洲欧洲第一视频| 亚洲国产精品va在看黑人| 欧美老肥婆性猛交视频| 亚洲aa在线观看| 大胆人体色综合| 欧美成在线视频| 国产精品美女免费视频| 在线性视频日韩欧美| 日韩欧美在线国产| 国产男女猛烈无遮挡91| 美日韩丰满少妇在线观看| 欧美国产第一页| 91精品久久久久久综合乱菊| 国产mv免费观看入口亚洲| 日韩亚洲成人av在线| 91精品国产高清久久久久久| 亚洲视频一区二区| 一区二区三区视频免费在线观看| 欧美在线国产精品| 国产精品v片在线观看不卡| 国产成人精品日本亚洲专区61| 热久久免费视频精品| 亚洲综合大片69999| 亚洲欧美日韩国产中文专区| 91精品久久久久久久久久久久久| 91成人免费观看网站| 精品国产欧美一区二区三区成人| 欧美另类老肥妇| 亚洲欧洲日产国码av系列天堂| 国产这里只有精品| 国产精品一区二区三区在线播放| 日韩高清免费观看| 午夜精品久久久久久99热| 欧日韩在线观看| 亚洲免费小视频| 91精品久久久久久久| 国产精品久久久久高潮| 亚洲的天堂在线中文字幕| 欧美视频在线观看免费网址| 日本在线精品视频| 久久青草福利网站| 欧美激情高清视频| 91久久精品美女| 欧美黄色性视频| 日本精品久久久久影院| 成人精品一区二区三区电影黑人| 日韩在线观看免费全集电视剧网站| 欧美肥老妇视频| 国产精品自产拍在线观看| 欧美黑人又粗大| 日韩精品在线看| 亚洲欧美国内爽妇网| 亚洲大胆人体在线| 超碰精品一区二区三区乱码| 亚洲伊人一本大道中文字幕| 国产成人精品最新| 精品国产一区二区三区久久狼黑人| 91av网站在线播放| 国产精品视频一区二区三区四| 丰满岳妇乱一区二区三区| 在线国产精品视频| 欧美大片va欧美在线播放| 美女扒开尿口让男人操亚洲视频网站| 视频一区视频二区国产精品| 97在线免费观看| 亚洲欧美制服丝袜| 成人av在线天堂| 亚洲a成v人在线观看| 久久精品视频va| 亚洲人成电影在线播放| 欧美性理论片在线观看片免费| 亚洲xxxx妇黄裸体| 91欧美精品成人综合在线观看| 国产成人精品免高潮费视频| 欧美中文在线观看| 成人福利视频在线观看| 日本一欧美一欧美一亚洲视频| 欧美激情手机在线视频| 欧美区二区三区| 91av视频在线| 久久激情视频免费观看| 久热爱精品视频线路一| 奇门遁甲1982国语版免费观看高清| 欧美做受高潮电影o| 日韩风俗一区 二区| 欧美中文字幕在线视频| 日韩欧美高清视频| 国产在线日韩在线| 亚洲性69xxxbbb| 日韩中文在线中文网在线观看| 欧美人在线视频| 欧美激情一区二区三区久久久| 中文字幕在线成人| 精品久久久久久久久久久| 欧美精品久久久久久久免费观看| 欧美日韩性视频| 亚洲第一网中文字幕| 日本午夜精品理论片a级appf发布| 午夜精品在线视频| 欧美日韩在线另类| 亚洲第一精品夜夜躁人人爽| 国产在线视频欧美| 亚洲的天堂在线中文字幕| 欧美激情久久久久久| 久久精品视频在线播放| 国产一区二区在线免费| 欧美久久精品午夜青青大伊人| 成人黄色av免费在线观看| 国产精品丝袜久久久久久不卡| 欧美一区二区三区精品电影| 超碰97人人做人人爱少妇| 日韩精品免费视频| 国产精品露脸av在线| 中文字幕亚洲一区在线观看| 久久久久久久久亚洲| 久久久久这里只有精品| 中文字幕国产精品久久| 久久精品国产亚洲| 日韩不卡中文字幕| 久久大大胆人体| 欧美激情免费视频| 精品视频—区二区三区免费| 国产精品一区二区三区久久久| 日韩极品精品视频免费观看| 精品国产91久久久久久老师| 欧美另类交人妖| 成人乱色短篇合集| 日韩中文有码在线视频| 久久成人精品一区二区三区| 欧美激情视频网站| 色偷偷91综合久久噜噜| 国产精品第一区| 国语自产在线不卡| 97超级碰碰人国产在线观看| 国产精品一区二区三| 精品中文字幕在线2019| 久久久久久网址| 国产成人亚洲综合91精品| 不卡av电影在线观看| 亚洲经典中文字幕| 欧美亚洲午夜视频在线观看|