zoukankan      html  css  js  c++  java
  • 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"/>     显示用户身份中的属性值

      当然每次这么做可能浪费的性能很不好,需要配置缓存。
  • 相关阅读:
    I Hate It(线段树点修改区间查询)
    DFS(dfs)
    时间复杂度和空间复杂度的简单讲解
    [转]matlab读取cvs文件的几种方法
    适合小白的大白话讲解 --->Git 与 Github 的区别
    [转]串口、COM口、UART口, TTL、RS-232、RS-485区别详解
    Pandas学习之(一)
    正规表示法
    Numpy解决问题实例--随机漫步
    Python 中range和xrange的详细区别
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13317764.html
Copyright © 2011-2022 走看看