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 进行权限验证_shiro整合Spring


3.创建一个applicationContext-shiro.xml,对shiro进行配置,内容如下: 


    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. "http://www.w3.org/2001/XMLSchema-instance"
    4. "http://www.springframework.org/schema/aop"
    5. "http://www.springframework.org/schema/tx"
    6. "http://www.springframework.org/schema/util"
    7. "http://www.springframework.org/schema/context"
    8.        xsi:schemaLocation="  
    9. //www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    10. //www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    11. //www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    12. //www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
    13. //www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    14.     <!-- =========================================================  
    15.          Shiro Components  
    16.          ========================================================= -->  
    17.   
    18. for
    19.          (use org.apache.shiro.web.mgt.DefaultWebSecurityManager instead when there is no web environment)-->  
    20. "securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
    21. 'realms'
    22.       property instead. -->  
    23. 2个方法  
    24. 1.  用户登录的验证(授权)  
    25. 2.  用户具有的角色和权限(认证)  
    26.  且看下面介绍-->  
    27. "realm" ref="sampleRealm"/>  
    28. this next property if
    29. default value is 'http'
    30.              Session implementation.  
    31. "sessionMode" value="native"/> -->  
    32.     </bean>  
    33.   
    34.     <!-- Post processor that automatically invokes init() and destroy() methods -->  
    35. "lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  
    36.     <!-- 自定义角色过滤器 支持多个角色可以访问同一个资源 eg:/home.jsp = authc,roleOR[admin,user]  用户有admin或者user角色 就可以访问-->  
    37. "roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/>  
    38.     <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -  
    39. this
    40.          to wire things with more control as well utilize nice Spring things such as  
    41. abstract beans or anything else
    42. "shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
    43. "securityManager" ref="securityManager"/>  
    44. "loginUrl" value="/page/login.jsp"/>  
    45. "successUrl" value="/page/index.jsp"/>  
    46. "unauthorizedUrl" value="/register/unauthorized"/>  
    47. 'filters'
    48. do
    49. default
    50. "filters">  
    51.             <util:map>  
    52. "authc">  
    53. class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>  
    54.                 </entry>  
    55.             </util:map>  
    56.         </property>  
    57. "filterChainDefinitions">  
    58.             <value>  
    59.                 /page/login.jsp = anon  
    60.                 /page/register/* = anon  
    61.                 /page/index.jsp = authc   
    62.                 /page/addItem* = authc,roles[数据管理员]  
    63.                 /page/file* = authc,roleOR[数据管理员,普通用户]  
    64.                 /page/listItems* = authc,roleOR[数据管理员,普通用户]  
    65.                 /page/showItem* = authc,roleOR[数据管理员,普通用户]  
    66.                 /page/updateItem*=authc,roles[数据管理员]  
    67.             </value>  
    68.         </property>  
    69.     </bean>  
    70.   
    71. </beans>


    其中的定义官网文档有详细的解释,这里不做描述! 
    然后在applicationContext.xml中引入该文件! 

    3. 实现sampleRealm,继承AuthorizingRealm,并重写认证授权方法 
    1) 我们首先创建两张表User,Role(这里只做最简单的基于用户-角色的权限验证,如果需要细粒度的控制,自己在添加权限表Permissions然后进行关联操作) 












      接下来我们看sampleRealm具体内容: 


        1. import
        2. import
        3. import
        4. import
        5. import
        6. import
        7. import
        8. import
        9. import
        10. import
        11. import
        12. import
        13. import
        14. import
        15.   
        16. import
        17. import
        18. import
        19.   
        20. /**
        21.  * The Spring/Hibernate sample application's one and only configured Apache Shiro Realm.
        22.  *
        23.  * <p>Because a Realm is really just a security-specific DAO, we could have just made Hibernate calls directly
        24.  * in the implementation and named it a 'HibernateRealm' or something similar.</p>
        25.  *
        26.  * <p>But we've decided to make the calls to the database using a UserDAO, since a DAO would be used in other areas
        27.  * of a 'real' application in addition to here. We felt it better to use that same DAO to show code re-use.</p>
        28.  */
        29. @Component
        30. public class SampleRealm extends
        31.       
        32. @Autowired
        33. private
        34.   
        35. public
        36. "SampleRealm"); //This name must match the name in the User class's getPrincipals() method
        37. //  setCredentialsMatcher(new Sha256CredentialsMatcher());
        38. new
        39.     }  
        40.   
        41.      
        42. //认证信息,主要针对用户登录,(下文讲述在action或者controller登录过程代码)
        43. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws
        44.         UsernamePasswordToken token = (UsernamePasswordToken) authcToken;  
        45.         
        46.         String  password = String.valueOf(token.getPassword());  
        47. //调用操作数据库的方法查询user信息
        48.         User user = userOperator.login( token.getUsername());  
        49. if( user != null
        50. if(password.equals(user.getPassword())){  
        51.                   Session session= SecurityUtils.getSubject().getSession();  
        52. "username", user.getLoginName());  
        53. return new
        54. else{  
        55. return null;  
        56.             }  
        57. else
        58. return null;  
        59.         }  
        60.     }  
        61. protected
        62.         String userId = (String) principals.fromRealm(getName()).iterator().next();  
        63.         User user = userOperator.getById(userId);  
        64. if( user != null
        65. new
        66.            Role role = userOperator.getByRoleId(user.getRoleId());  
        67.                 info.addRole(role.getRoleName());  
        68. //  info.addStringPermissions( role.getPermissions() );//如果你添加了对权限的表,打开此注释,添加角色具有的权限
        69.               
        70. return
        71. else
        72. return null;  
        73.         }  
        74.     }  
        75.   
        76. }


        --注意shiro配置文件中 
        <bean id="roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/> 
        OneRoleAuthorizationFilter:为验证多个角色可以访问同一个资源的定义:
         


        1. import
        2. import
        3.   
        4. import
        5. import
        6.   
        7. import
        8. import
        9. import
        10.   
        11. public class OneRoleAuthorizationFilter extends
        12.   
        13. @SuppressWarnings({"unchecked"})  
        14. public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws
        15.   
        16.             Subject subject = getSubject(request, response);  
        17.             String[] rolesArray = (String[]) mappedValue;  
        18.   
        19. if (rolesArray == null || rolesArray.length == 0) {  
        20. //no roles specified, so nothing to check - allow access.
        21. return true;  
        22.             }  
        23. boolean flag = false;  
        24.             Set<String> roles = CollectionUtils.asSet(rolesArray);  
        25. for
        26. if(subject.hasRole(string)){  
        27. true;  
        28.                 }  
        29.             }  
        30. return
        31.         }  
        32.   
        33. }

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

        这里主要说明index.jsp 

        Shiro具有自己的JSP / GSP Tag Library,用户做权限检查判断等等 

        所以我们在index.jsp引入shiro 标签库 


        Apache Shiro 整合Spring 进行权限验证_apache_02

         

        里面用很多的标签,这里我们主要说明: 


        Apache Shiro 整合Spring 进行权限验证_shiro整合Spring_03

         

        如果用户具有administrator 角色我们就给他显示这个链接 


        Apache Shiro 整合Spring 进行权限验证_spring_04

         

        如果用户有user:create权限 我们显示此链接 

        根据我上文提到的user和role表中的数据,我们在index.jsp,做如下测试: 

        <shiro:hasRole name="数据管理员”> 

        您好管理员同志! 

            </shiro:hasRole> 

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

        您好普通用户! 

            </shiro:hasRole> 

        5. jsp页面写完后,接下来我们看UserAction(用户登录,退出等操作): 

        1. //登录
        2. public
        3. UsernamePasswordToken token = new
        4. try
        5.             SecurityUtils.getSubject().login(token);  
        6.                   
        7. catch
        8. "/page/login.jsp";  
        9. return "redirect";  
        10.         }  
        11. "/page/index.jsp";  
        12. return "redirect";  
        13.     }  
        14. //注销
        15. public
        16.         SecurityUtils.getSubject().logout();  
        17. "/login.jsp";  
        18. return "redirect";  
        19.     }

        至此基本结束,启动项目,就可以体验shiro的安全控制了 嘿嘿 


        下面说freemarker中使用shiro标签 

        这个网上一搜索就能找到答案,已经由James Gregory把代码上传到GitHub, 

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

        下载该jar包 或者源代码文件复制到自己工程的lib下或者package中 

        我是讲文件复制到自己的package中使用: 



        Apache Shiro 整合Spring 进行权限验证_spring_05

         


        如果你使用spring MVC 

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

        如果你单独使用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: 


        1. import
        2.      
        3. import
        4.      
        5. import
        6. import
        7.      
        8. public class MyFreemarkerManager extends
        9.      
        10. @Override
        11. protected Configuration createConfiguration(ServletContext servletContext) throws
        12. super.createConfiguration(servletContext);     
        13. "shiro", new
        14. return
        15.     }     
        16. }


        然后在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> 

         

        ----------------------------shiro内置过滤器研究-------------------------------------------

        anon

        org.apache.shiro.web.filter.authc.AnonymousFilter

        authc

        org.apache.shiro.web.filter.authc.FormAuthenticationFilter

        authcBasic

        org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

        perms

        org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

        port

        org.apache.shiro.web.filter.authz.PortFilter

        rest

        org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

        roles

        org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

        ssl

        org.apache.shiro.web.filter.authz.SslFilter

        user

        org.apache.shiro.web.filter.authc.UserFilter

         


        rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。


        port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString


        是你访问的url里的?后面的参数。


        perms:例子/admins/user/**=perms[user:add:*],perms参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于


        isPermitedAll()方法。


        roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如/admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。


        anon:例子/admins/**=anon 没有参数,表示可以匿名使用。


        authc:例如/admins/user/**=authc表示需要认证才能使用,没有参数


        authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证


        ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https


        user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查


         


        这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。其中anon,authcBasic,auchc,user是第一组,


        perms,roles,ssl,rest,port是第二组