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

    xiaoxiao2021-04-03  38

    [html]   view plain  copy  print ? </pre><pre name="code" class="html"><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">           <property name="securityManager" ref="securityManager"/>           <property name="loginUrl" value="/login"/>            <property name="successUrl" value="/first" />           <property name="filters">               <util:map>                   <entry key="authc" value-ref="formAuthenticationFilter"/>               </util:map>           </property>           <property name="filterChainDefinitions">               <value>                   <!-- 对静态资源不需要进行认证 -->                   /images/** = anon                   /js/** = anon                   /styles/** = anon                   <!-- 对所有url都需要进行认证 -->                   /logout = logout                   /** = authc               </value>           </property>       </bean>  

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

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

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

    [html]   view plain  copy  print ? <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">   <%@ page contentType="text/html; charset=UTF-8"%>   <%@ include file="/WEB-INF/jsp/tag.jsp"%>   <html>   <head>   <TITLE>药品采购平台</TITLE>   <meta http-equiv="pragma" content="no-cache">   <meta http-equiv="cache-control" content="no-cache">   <meta http-equiv="content-type" content="text/html; charset=UTF-8">      <LINK rel="stylesheet" type="text/css" href="${baseurl}styles/style.css">   <LINK rel="stylesheet" type="text/css" href="${baseurl}styles/login.css">   <LINK rel="stylesheet" type="text/css"   href="${baseurl}js/easyui/themes/default/easyui.css">   <LINK rel="stylesheet" type="text/css"   href="${baseurl}js/easyui/themes/icon.css">      <STYLE type="text/css">   .btnalink {       cursor: hand;       display: block;       width: 80px;       height: 29px;       float: left;       margin: 12px 28px 12px auto;       line-height: 30px;       background: url('${baseurl}images/login/btnbg.jpg') no-repeat;       font-size: 14px;       color: #fff;       font-weight: bold;       text-decoration: none;   }   </STYLE>   <%@ include file="/WEB-INF/jsp/common_js.jsp"%>      <script type="text/javascript">          //登录提示方法       function loginsubmit() {           $("#loginform").submit();          }          </SCRIPT>   </HEAD>   <BODY style="background: #f6fdff url(${baseurl}images/login/bg1.jpg) repeat-x;">       <FORM id="loginform" name="loginform" action=""           method="post">           <DIV class="logincon">                  <DIV class="title">                   <IMG alt="" src="${baseurl}images/login/logo.png">               </DIV>                  <DIV class="cen_con">                   <IMG alt="" src="${baseurl}images/login/bg2.png">               </DIV>                  <DIV class="tab_con">                      <input type="password" style="display:none;" />                   <TABLE class="tab" border="0" cellSpacing="6" cellPadding="8">                       <TBODY>                           <TR>                               <TD>用户名:</TD>                               <TD colSpan="2"><input type="text" id="usercode"                                   name="username" style="WIDTH: 130px" /></TD>                           </TR>                           <TR>                               <TD>密 码:</TD>                               <TD><input type="password" id="pwd" name="password" style="WIDTH: 130px" />                               </TD>                           </TR>                           <%-- <TR>                               <TD>验证码:</TD>                               <TD><input id="randomcode" name="randomcode" size="8" /> <img                                   id="randomcode_img" src="${baseurl}validatecode.jsp" alt=""                                   width="56" height="20" align='absMiddle' /> <a                                   href=javascript:randomcode_refresh()>刷新</a></TD>                           </TR> --%>                              <TR>                               <TD colSpan="2" align="center"><input type="button"                                   class="btnalink" onclick="loginsubmit()" value="登  录" />                                   <input type="reset" class="btnalink" value="重  置" /></TD>                           </TR>                       </TBODY>                   </TABLE>                  </DIV>           </DIV>       </FORM>   </BODY>   </HTML>   form过滤器有个特点就是,只要是表单提交(条件:1.post   2.action路径为"")就相当于:

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

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

    [html]   view plain  copy  print ? /**        * 身份认证        */       @Override       protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {           String userName = (String) token.getPrincipal();           User user = userService.findByUsername(userName);                      if(user == null) {               //抛出用户不存在异常               throw new UnknownAccountException();//没找到帐号           }           if(user.getLocked()) {               //抛出用户被锁定异常               throw new LockedAccountException(); //帐号锁定           }           // 如果查询到返回认证信息AuthenticationInfo           SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, user.getPassword(),ByteSource.Util.bytes(user.getCredentialsSalt()),                   this.getName());              return simpleAuthenticationInfo;       }   值得注意的是SimpleAuthenticationInfo这个方法的构造函数,因为它决定了凭证认证的方式:

    1.

    [html]   view plain  copy  print ? public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {        this.principals = new SimplePrincipalCollection(principal, realmName);        this.credentials = credentials;    }   该构造器对应的默认任凭类,什么都不需要输入,没有加密算法,没有迭代次数,直接通过用户名和密码进行进行验证就可以。

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

    2.

    [html]   view plain  copy  print ? public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {         this.principals = new SimplePrincipalCollection(principal, realmName);         this.credentials = hashedCredentials;         this.credentialsSalt = credentialsSalt;     }   这个和你加密的密码salt有关:

    [html]   view plain  copy  print ? package com.lgy.service;      import org.apache.shiro.crypto.RandomNumberGenerator;   import org.apache.shiro.crypto.SecureRandomNumberGenerator;   import org.apache.shiro.crypto.hash.SimpleHash;   import org.apache.shiro.util.ByteSource;   import org.springframework.beans.factory.annotation.Value;   import org.springframework.stereotype.Service;      import com.lgy.model.User;          @Service   public class PasswordHelper {       private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();          @Value("${password.algorithmName}")       private String algorithmName;       @Value("${password.hashIterations}")       private int hashIterations;          public void encryptPassword(User user) {              user.setSalt(randomNumberGenerator.nextBytes().toHex());              String newPassword = new SimpleHash(                   algorithmName,           //加密算法                   user.getPassword(),      //密码                   ByteSource.Util.bytes(user.getCredentialsSalt()),  //salt盐   username + salt                   hashIterations   //迭代次数                   ).toHex();              user.setPassword(newPassword);       }   }   所以需要设置凭证信息:

    [html]   view plain  copy  print ? <!-- Realm实现 -->       <bean id="userRealm" class="com.lgy.web.shiro.UserRealm">           <!-- 设置认证凭证器 -->           <property name="credentialsMatcher" ref="credentialsMatcher" />       </bean>               <!-- 认证凭证器 -->       <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">           <!-- 算法名称 -->           <property name="hashAlgorithmName" value="${password.algorithmName}" />           <!-- 迭代次数 -->           <property name="hashIterations" value="${password.hashIterations}" />       </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 ? <?xml version="1.0" encoding="UTF-8"?>   <beans xmlns="http://www.springframework.org/schema/beans"          xmlns:util="http://www.springframework.org/schema/util"          xmlns:aop="http://www.springframework.org/schema/aop"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd          http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">          <aop:config proxy-target-class="true"></aop:config>       <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">           <property name="securityManager" ref="securityManager"/>       </bean>   </beans>   在控制器中:

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

    [html]   view plain  copy  print ? /**        * 授权认证        */       @Override       protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {           User user = (User) principals.getPrimaryPrincipal();           SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();           authorizationInfo.setRoles(userService.findRoles(user.getUsername()));           authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));           return authorizationInfo;       }            权限比较可能有如下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 ? /**        * 授权认证        */       @Override       protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {           User user = (User) principals.getPrimaryPrincipal();           SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();           authorizationInfo.setRoles(userService.findRoles(user.getUsername()));           authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));           return authorizationInfo;       }  

    相当于他们调用了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://ju.6miu.com/read-666024.html

    最新回复(0)