天天看點

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

Apache Shiro是什麼?

Apache Shiro是一個功能強大且易于使用的Java安全架構,進行認證,授權,加密和會話管理。随着Shiro的易于了解的API,你可以快速,輕松地確定任何應用程式 - 移動應用從最小的到最大的Web和企業應用。

如何使用Apache Shiro(這裡指與Spring 內建)?

1. 首先去官方網站下載下傳相關jar包(這裡使用1.2.2版本),其中包括:

shiro-core-1.2.2.jar

shiro-spring-1.2.2.jar

shiro-web-1.2.2.jar

(還需要slf4j相關jar支援)

2.在web.xml中配置shiroFilter(注意這個filter一定要放在所有的filter之前,否則不能成功使用)

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

3.建立一個applicationContext-shiro.xml,對shiro進行配置,内容如下:

Java代碼  

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xmlns:tx="http://www.springframework.org/schema/tx"  
  6.        xmlns:util="http://www.springframework.org/schema/util"  
  7.        xmlns:context="http://www.springframework.org/schema/context"  
  8.        xsi:schemaLocation="  
  9.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  10.        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd  
  11.        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd  
  12.        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd  
  13.        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  
  14.     <!-- =========================================================  
  15.          Shiro Components  
  16.          ========================================================= -->  
  17.     <!-- Shiro's main business-tier object for web-enabled applications  
  18.          (use org.apache.shiro.web.mgt.DefaultWebSecurityManager instead when there is no web environment)-->  
  19.     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
  20.         <!-- Single realm app (realm configured next, below).  If you have multiple realms, use the 'realms'  
  21.       property instead. -->  
  22.     <!--這裡的sampleRealm需要我們自己實作,主要包括2個方法  
  23. 1.  使用者登入的驗證(授權)  
  24. 2.  使用者具有的角色和權限(認證)  
  25.  且看下面介紹-->  
  26.         <property name="realm" ref="sampleRealm"/>  
  27.         <!-- Uncomment this next property if you want heterogenous session access or clusterable/distributable  
  28.              sessions.  The default value is 'http' which uses the Servlet container's HttpSession as the underlying  
  29.              Session implementation.  
  30.         <property name="sessionMode" value="native"/> -->  
  31.     </bean>  
  32.     <!-- Post processor that automatically invokes init() and destroy() methods -->  
  33.     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  
  34.     <!-- 自定義角色過濾器 支援多個角色可以通路同一個資源 eg:/home.jsp = authc,roleOR[admin,user]  使用者有admin或者user角色 就可以通路-->  
  35.      <bean id="roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/>  
  36.     <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -  
  37.          web.xml uses the DelegatingFilterProxy to access this bean.  This allows us  
  38.          to wire things with more control as well utilize nice Spring things such as  
  39.          PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->  
  40.     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
  41.         <property name="securityManager" ref="securityManager"/>  
  42.         <property name="loginUrl" value="/page/login.jsp"/>  
  43.         <property name="successUrl" value="/page/index.jsp"/>  
  44.         <property name="unauthorizedUrl" value="/register/unauthorized"/>  
  45.         <!-- The 'filters' property is usually not necessary unless performing an override, which we  
  46.              want to do here (make authc point to a PassthruAuthenticationFilter instead of the  
  47.              default FormAuthenticationFilter: -->  
  48.         <property name="filters">  
  49.             <util:map>  
  50.                 <entry key="authc">  
  51.                     <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>  
  52.                 </entry>  
  53.             </util:map>  
  54.         </property>  
  55.         <property name="filterChainDefinitions">  
  56.             <value>  
  57.                 /page/login.jsp = anon  
  58.                 /page/register  
  59. @Component  
  60. public class SampleRealm extends AuthorizingRealm {  
  61.      @Autowired  
  62.      private UserOperator userOperator;  
  63.     public SampleRealm() {  
  64.         setName("SampleRealm"); //This name must match the name in the User class's getPrincipals() method  
  65.       //  setCredentialsMatcher(new Sha256CredentialsMatcher());  
  66.         setCredentialsMatcher(new AllowAllCredentialsMatcher());  
  67.     }  
  68. //認證資訊,主要針對使用者登入,(下文講述在action或者controller登入過程代碼)  
  69.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {  
  70.         UsernamePasswordToken token = (UsernamePasswordToken) authcToken;  
  71.         String  password = String.valueOf(token.getPassword());  
  72. //調用操作資料庫的方法查詢user資訊  
  73.         User user = userOperator.login( token.getUsername());  
  74.         if( user != null ) {  
  75.             if(password.equals(user.getPassword())){  
  76.                   Session session= SecurityUtils.getSubject().getSession();  
  77.                   session.setAttribute("username", user.getLoginName());  
  78.             return new SimpleAuthenticationInfo(user.getUserId(), user.getPassword(), getName());  
  79.             }else{  
  80.                 return null;  
  81.             }  
  82.         } else {  
  83.             return null;  
  84.         }  
  85.     }  
  86. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
  87.         String userId = (String) principals.fromRealm(getName()).iterator().next();  
  88.         User user = userOperator.getById(userId);  
  89.         if( user != null ) {  
  90.             SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();  
  91.            Role role = userOperator.getByRoleId(user.getRoleId());  
  92.                 info.addRole(role.getRoleName());  
  93.               //  info.addStringPermissions( role.getPermissions() );//如果你添加了對權限的表,打開此注釋,添加角色具有的權限  
  94.             return info;  
  95.         } else {  
  96.             return null;  
  97.         }  
  98.     }  
  99. }  

--注意shiro配置檔案中

<bean id="roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/>

OneRoleAuthorizationFilter:為驗證多個角色可以通路同一個資源的定義:

Java代碼  

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽
  1. import java.io.IOException;  
  2. import java.util.Set;  
  3. import javax.servlet.ServletRequest;  
  4. import javax.servlet.ServletResponse;  
  5. import org.apache.shiro.subject.Subject;  
  6. import org.apache.shiro.util.CollectionUtils;  
  7. import org.apache.shiro.web.filter.authz.AuthorizationFilter;  
  8. public class OneRoleAuthorizationFilter extends AuthorizationFilter{  
  9.      @SuppressWarnings({"unchecked"})  
  10.         public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {  
  11.             Subject subject = getSubject(request, response);  
  12.             String[] rolesArray = (String[]) mappedValue;  
  13.             if (rolesArray == null || rolesArray.length == 0) {  
  14.                 //no roles specified, so nothing to check - allow access.  
  15.                 return true;  
  16.             }  
  17.             boolean flag = false;  
  18.             Set<String> roles = CollectionUtils.asSet(rolesArray);  
  19.             for (String string : roles) {  
  20.                 if(subject.hasRole(string)){  
  21.                     flag = true;  
  22.                 }  
  23.             }  
  24.             return flag;  
  25.         }  
  26. }  

4. 在工程WebRoot/page下,建立login.jsp,index.jsp,register.jsp;

這裡主要說明index.jsp

Shiro具有自己的JSP / GSP Tag Library,使用者做權限檢查判斷等等

是以我們在index.jsp引入shiro 标簽庫

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

裡面用很多的标簽,這裡我們主要說明:

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

如果使用者具有administrator 角色我們就給他顯示這個連結

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

如果使用者有user:create權限 我們顯示此連結

根據我上文提到的user和role表中的資料,我們在index.jsp,做如下測試:

<shiro:hasRole name="資料管理者”>

您好管理者同志!

    </shiro:hasRole>

<shiro:hasRole name="普通使用者”>

您好普通使用者!

    </shiro:hasRole>

5. jsp頁面寫完後,接下來我們看UserAction(使用者登入,退出等操作):

Java代碼  

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽
  1. //登入  
  2.         public String login(){  
  3. UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword());  
  4.         try {  
  5.             SecurityUtils.getSubject().login(token);  
  6.         } catch (AuthenticationException e) {  
  7.             redirectPath="/page/login.jsp";  
  8.             return "redirect";  
  9.         }  
  10.         redirectPath="/page/index.jsp";  
  11.         return "redirect";  
  12.     }  
  13. //登出  
  14.     public String loginout(){  
  15.         SecurityUtils.getSubject().logout();  
  16.          redirectPath="/login.jsp";  
  17.             return "redirect";  
  18.     }  

至此基本結束,啟動項目,就可以體驗shiro的安全控制了 嘿嘿

下面說freemarker中使用shiro标簽

這個網上一搜尋就能找到答案,已經由James Gregory把代碼上傳到GitHub,

位址:https://github.com/jagregory/shiro-freemarker-tags

下載下傳該jar包 或者源代碼檔案複制到自己工程的lib下或者package中

我是講檔案複制到自己的package中使用:

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽

一:如果你使用spring MVC

請看http://www.woxplife.com/articles/473.html

目前Freemarker對Shrio的标簽還不支援,不過已經有人貢獻出來第三方面解決方案,如下:

1、下載下傳shiro-freemarker-tags

GitHub位址:https://github.com/jagregory/shiro-freemarker-tags

可以先看一下他的說明文檔,有一個初步的了解。

2、Spring MVC配置

自定義一個ShiroTagFreeMarkerConfigurer繼承Spring本身提供的FreeMarkerConfigurer,目的是在FreeMarker的Configuration中添加shiro的配置

public class ShiroTagFreeMarkerConfigurer extends FreeMarkerConfigurer {
 
    @Override
    public void afterPropertiesSet() throws IOException, TemplateException {
        super.afterPropertiesSet();
        this.getConfiguration().setSharedVariable("shiro", new ShiroTags());
    }
     
}
           

 下面的Spring mvc配置

<bean id="freemakerCongfig"
    class="com.xxx.web.freemarker.ShiroTagFreeMarkerConfigurer">
    <property name="templateLoaderPath" value="/WEB-INF/views/" />
    <property name="freemarkerSettings">
        <props>
            <prop key="defaultEncoding">UTF-8</prop>
            <prop key="classic_compatible">true</prop>
        </props>
    </property>
</bean>      

3、使用Shiro Tag

<@shiro.guest>Hello guest!</@shiro.guest>      

二:如果你單獨使用Freemarker 比如使用模闆生成靜态頁

在相關的類中加入如下代碼:

Configuration cfg = new Configuration();

cfg.setDefaultEncoding(“UTF-8”);

cfg.setSharedVariable("shiro", new ShiroTags());

然後在ftl頁面中使用tag:

<@shiro.hasRole name=”admin”>Hello admin!</@shiro.hasRole>

三:如果是使用struts2內建的freemarker作為頁面渲染

可以寫一個類extend    Struts2的FreemarkerManager:

Java代碼  

Apache Shiro 整合Spring 進行權限驗證 以及在Freemarker中使用shiro标簽
  1. import javax.servlet.ServletContext;     
  2. import org.apache.struts2.views.freemarker.FreemarkerManager;     
  3. import freemarker.template.Configuration;     
  4. import freemarker.template.TemplateException;     
  5. public class MyFreemarkerManager extends FreemarkerManager {     
  6.     @Override     
  7.     protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException {     
  8.         Configuration cfg = super.createConfiguration(servletContext);     
  9.        cfg.setSharedVariable("shiro", new ShiroTags());  
  10.         return cfg;     
  11.     }     
  12. }  

然後在struts.xml中指定struts使用我們自己擴充的 FreemarkerManager

<constant name="struts.freemarker.manager.classname"  

    value="com.xxx.xxx.MyFreemarkerManager" /> 

然後在頁面中

然後在ftl頁面中使用tag:

<@shiro.hasRole name=”admin”>Hello admin!</@shiro.hasRole>

繼續閱讀