shiro权限框架中的认证和授权过程

[html] view plain copy
 print?
  1. </pre><pre name="code" class="html"><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
  2.         <property name="securityManager" ref="securityManager"/>  
  3.         <property name="loginUrl" value="/login"/>   
  4.         <property name="successUrl" value="/first" />  
  5.         <property name="filters">  
  6.             <util:map>  
  7.                 <entry key="authc" value-ref="formAuthenticationFilter"/>  
  8.             </util:map>  
  9.         </property>  
  10.         <property name="filterChainDefinitions">  
  11.             <value>  
  12.                 <!-- 对静态资源不需要进行认证 -->  
  13.                 /images/** = anon  
  14.                 /js/** = anon  
  15.                 /styles/** = anon  
  16.                 <!-- 对所有url都需要进行认证 -->  
  17.                 /logout = logout  
  18.                 /** = authc  
  19.             </value>  
  20.         </property>  
  21.     </bean>  

首先看一下Shiro中的web filter过滤器:

         默认采用的认证过滤器filter是表单过滤器,默认登录的url是/login(只要没有认证的都会跳转到/login路径下),辅助登录成功url是/first。


默认登录url跳转到的页面是login.jsp如下:

[html] view plain copy
 print?
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  2. <%@ page contentType="text/html; charset=UTF-8"%>  
  3. <%@ include file="/WEB-INF/jsp/tag.jsp"%>  
  4. <html>  
  5. <head>  
  6. <TITLE>药品采购平台</TITLE>  
  7. <meta http-equiv="pragma" content="no-cache">  
  8. <meta http-equiv="cache-control" content="no-cache">  
  9. <meta http-equiv="content-type" content="text/html; charset=UTF-8">  
  10.   
  11. <LINK rel="stylesheet" type="text/css" href="${baseurl}styles/style.css">  
  12. <LINK rel="stylesheet" type="text/css" href="${baseurl}styles/login.css">  
  13. <LINK rel="stylesheet" type="text/css"   href="${baseurl}js/easyui/themes/default/easyui.css">  
  14. <LINK rel="stylesheet" type="text/css"   href="${baseurl}js/easyui/themes/icon.css">  
  15.   
  16. <STYLE type="text/css">  
  17. .btnalink {  
  18.     cursor: hand;  
  19.     display: block;  
  20.      80px;  
  21.     height: 29px;  
  22.     float: left;  
  23.     margin: 12px 28px 12px auto;  
  24.     line-height: 30px;  
  25.     background: url('${baseurl}images/login/btnbg.jpg') no-repeat;  
  26.     font-size: 14px;  
  27.     color: #fff;  
  28.     font-weight: bold;  
  29.     text-decoration: none;  
  30. }  
  31. </STYLE>  
  32. <%@ include file="/WEB-INF/jsp/common_js.jsp"%>  
  33.   
  34. <script type="text/javascript">  
  35.   
  36.     //登录提示方法  
  37.     function loginsubmit() {  
  38.         $("#loginform").submit();  
  39.   
  40.     }  
  41.       
  42. </SCRIPT>  
  43. </HEAD>  
  44. <BODY style="background: #f6fdff url(${baseurl}images/login/bg1.jpg) repeat-x;">  
  45.     <FORM id="loginform" name="loginform" action=""  
  46.         method="post">  
  47.         <DIV class="logincon">  
  48.   
  49.             <DIV class="title">  
  50.                 <IMG alt="" src="${baseurl}images/login/logo.png">  
  51.             </DIV>  
  52.   
  53.             <DIV class="cen_con">  
  54.                 <IMG alt="" src="${baseurl}images/login/bg2.png">  
  55.             </DIV>  
  56.   
  57.             <DIV class="tab_con">  
  58.   
  59.                 <input type="password" style="display:none;" />  
  60.                 <TABLE class="tab" border="0" cellSpacing="6" cellPadding="8">  
  61.                     <TBODY>  
  62.                         <TR>  
  63.                             <TD>用户名:</TD>  
  64.                             <TD colSpan="2"><input type="text" id="usercode"  
  65.                                 name="username" style="WIDTH: 130px" /></TD>  
  66.                         </TR>  
  67.                         <TR>  
  68.                             <TD>密 码:</TD>  
  69.                             <TD><input type="password" id="pwd" name="password" style="WIDTH: 130px" />  
  70.                             </TD>  
  71.                         </TR>  
  72.                         <%-- <TR>  
  73.                             <TD>验证码:</TD>  
  74.                             <TD><input id="randomcode" name="randomcode" size="8" /> <img  
  75.                                 id="randomcode_img" src="${baseurl}validatecode.jsp" alt=""  
  76.                                 width="56" height="20" align='absMiddle' /> <a  
  77.                                 href=javascript:randomcode_refresh()>刷新</a></TD>  
  78.                         </TR> --%>  
  79.   
  80.                         <TR>  
  81.                             <TD colSpan="2" align="center"><input type="button"  
  82.                                 class="btnalink" onclick="loginsubmit()" value="登  录" />  
  83.                                 <input type="reset" class="btnalink" value="重  置" /></TD>  
  84.                         </TR>  
  85.                     </TBODY>  
  86.                 </TABLE>  
  87.   
  88.             </DIV>  
  89.         </DIV>  
  90.     </FORM>  
  91. </BODY>  
  92. </HTML>  

form过滤器有个特点就是,只要是表单提交(条件:1.post   2.action路径为"")就相当于:

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

他会自动到Real中的方法进行身份认证:

[html] view plain copy
 print?
  1. /**  
  2.      * 身份认证  
  3.      */  
  4.     @Override  
  5.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
  6.         String userName = (String) token.getPrincipal();  
  7.         User user = userService.findByUsername(userName);  
  8.           
  9.         if(user == null) {  
  10.             //抛出用户不存在异常  
  11.             throw new UnknownAccountException();//没找到帐号  
  12.         }  
  13.         if(user.getLocked()) {  
  14.             //抛出用户被锁定异常  
  15.             throw new LockedAccountException(); //帐号锁定  
  16.         }  
  17.         // 如果查询到返回认证信息AuthenticationInfo  
  18.         SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, user.getPassword(),ByteSource.Util.bytes(user.getCredentialsSalt()),  
  19.                 this.getName());  
  20.   
  21.         return simpleAuthenticationInfo;  
  22.     }  

值得注意的是SimpleAuthenticationInfo这个方法的构造函数,因为它决定了凭证认证的方式:

1.

[html] view plain copy
 print?
  1. public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {  
  2.      this.principals = new SimplePrincipalCollection(principal, realmName);  
  3.      this.credentials = credentials;  
  4.  }  

该构造器对应的默认任凭类,什么都不需要输入,没有加密算法,没有迭代次数,直接通过用户名和密码进行进行验证就可以。

[html] view plain copy
 print?
  1. <bean id="userRealm" class="com.lgy.web.shiro.UserRealm">  
  2.         <!-- 设置认证凭证器 -->  
  3.         <!--<property name="credentialsMatcher" ref="credentialsMatcher" /> -->  
  4.     </bean>  


2.

[html] view plain copy
 print?
  1. public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {  
  2.       this.principals = new SimplePrincipalCollection(principal, realmName);  
  3.       this.credentials = hashedCredentials;  
  4.       this.credentialsSalt = credentialsSalt;  
  5.   }  

这个和你加密的密码salt有关:

[html] view plain copy
 print?
  1. package com.lgy.service;  
  2.   
  3. import org.apache.shiro.crypto.RandomNumberGenerator;  
  4. import org.apache.shiro.crypto.SecureRandomNumberGenerator;  
  5. import org.apache.shiro.crypto.hash.SimpleHash;  
  6. import org.apache.shiro.util.ByteSource;  
  7. import org.springframework.beans.factory.annotation.Value;  
  8. import org.springframework.stereotype.Service;  
  9.   
  10. import com.lgy.model.User;  
  11.       
  12. @Service  
  13. public class PasswordHelper {  
  14.     private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();  
  15.   
  16.     @Value("${password.algorithmName}")  
  17.     private String algorithmName;  
  18.     @Value("${password.hashIterations}")  
  19.     private int hashIterations;  
  20.   
  21.     public void encryptPassword(User user) {  
  22.   
  23.         user.setSalt(randomNumberGenerator.nextBytes().toHex());  
  24.   
  25.         String newPassword = new SimpleHash(  
  26.                 algorithmName,           //加密算法  
  27.                 user.getPassword(),      //密码  
  28.                 ByteSource.Util.bytes(user.getCredentialsSalt()),  //salt盐   username + salt  
  29.                 hashIterations   //迭代次数  
  30.                 ).toHex();  
  31.   
  32.         user.setPassword(newPassword);  
  33.     }  
  34. }  

所以需要设置凭证信息:

[html] view plain copy
 print?
  1. <!-- Realm实现 -->  
  2.     <bean id="userRealm" class="com.lgy.web.shiro.UserRealm">  
  3.         <!-- 设置认证凭证器 -->  
  4.         <property name="credentialsMatcher" ref="credentialsMatcher" />  
  5.     </bean>  
  6.        
  7.     <!-- 认证凭证器 -->  
  8.     <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">  
  9.         <!-- 算法名称 -->  
  10.         <property name="hashAlgorithmName" value="${password.algorithmName}" />  
  11.         <!-- 迭代次数 -->  
  12.         <property name="hashIterations" value="${password.hashIterations}" />  
  13.     </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的配置文件中配置注解启动:

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:util="http://www.springframework.org/schema/util"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  6.        xsi:schemaLocation="  
  7.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  8.        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd  
  9.        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">  
  10.   
  11.     <aop:config proxy-target-class="true"></aop:config>  
  12.     <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
  13.         <property name="securityManager" ref="securityManager"/>  
  14.     </bean>  
  15. </beans>  

在控制器中:

[html] view plain copy
 print?
  1. @RequiresPermissions("user:create")  
  2. @RequestMapping(value = "/create"method = RequestMethod.GET)  
  3. public String showCreateForm(Model model) {  
  4.     //...  
  5.     return "user/edit";  
  6. }  
当进入到这个Controller中的时候,会先进入realm中的:

[html] view plain copy
 print?
  1. /**  
  2.      * 授权认证  
  3.      */  
  4.     @Override  
  5.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
  6.         User user = (User) principals.getPrimaryPrincipal();  
  7.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();  
  8.         authorizationInfo.setRoles(userService.findRoles(user.getUsername()));  
  9.         authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));  
  10.         return authorizationInfo;  
  11.     }  

         权限比较可能有如下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中的:

[html] view plain copy
 print?
  1. /**  
  2.      * 授权认证  
  3.      */  
  4.     @Override  
  5.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
  6.         User user = (User) principals.getPrimaryPrincipal();  
  7.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();  
  8.         authorizationInfo.setRoles(userService.findRoles(user.getUsername()));  
  9.         authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));  
  10.         return authorizationInfo;  
  11.     }  


相当于他们调用了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"/>     显示用户身份中的属性值

  当然每次这么做可能浪费的性能很不好,需要配置缓存。
原文地址:https://www.cnblogs.com/hzcya1995/p/13317764.html