Shiro (包含权限满足其中一个就通过的用法)

方法/步骤

  1. web.xml添加配置


    <!-- shiro过滤器 -->

     <filter>

      <filter-name>shiroFilter</filter-name>

      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

      <init-param>

       <param-name>targetFilterLifecycle</param-name>

       <param-value>true</param-value>

      </init-param>

     </filter>

     <filter-mapping>

      <filter-name>shiroFilter</filter-name>

      <url-pattern>/*</url-pattern>

     </filter-mapping>

  2. shiro与spring整合配置


    <!-- 使用shiro安全检查注解 -->

     <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />

     

     <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

      <property name="securityManager" ref="securityManager" />

     </bean>



     <!-- shiro的生命周期处理器 -->

     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

     

     <!-- shiro自带的密码匹配器(用来校验密码足够了) -->

      <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.SimpleCredentialsMatcher"></bean> 

     <!-- security datasource: -->

     <bean id="myRealm" class="cc.eguid.service.shiro.MyRealm">

      <property name="credentialsMatcher" ref="credentialsMatcher"/><!-- 密码匹配器 -->

            <property name="cachingEnabled" value="false"/><!-- 禁止缓存 -->

     </bean>

     <!-- 安全管理器 -->

     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

      <property name="realm" ref="myRealm" />

     </bean>

     <!-- shiro过滤器 -->

     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

      <!-- 配置安全管理器 -->

      <property name="securityManager" ref="securityManager" />

      <!-- 身份认证失败跳转的地址 -->

      <property name="loginUrl" value="/login/" />

      <!-- 身份认证成功跳转的地址 -->

      <property name="successUrl" value="/" />

      <!-- 权限认证失败跳转的地址 -->

      <property name="unauthorizedUrl" value="/login/unauthorized" />

      <property name="filterChainDefinitions">

       <!--anon 表示匿名访问,不需要认证以及授权 -->

       <!--authc表示需要认证 没有进行身份认证是不能进行访问的 -->

       <!--authc,roles[admin]表示是admin角色的用户才能访问 -->

       <value>

        /static/** = anon

        /login/** = anon

        /common/** = anon

        /admin/** = authc,roles[admin]

        /* = authc

        /** = authc

       </value>

      </property>

     </bean>

     

  3. realm和自定义密码校验器实现


    public class MyRealm extends AuthorizingRealm{

     Logger log=Logger.getLogger(MyRealm.class);

     

     @Autowired

        private UserService userService;//这是自己实现的用户信息操作类,实现用户信息,用户角色信息、用户权限信息查询功能

     

     @Override

     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

      UserInfo user = (UserInfo) principals.getPrimaryPrincipal();

      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

      // 查询角色信息

      Collection<String> roles = userService.findRoles(user);

      info.addRoles(roles);

      log.info("shiro获取用户所属角色列表:"+roles);

      // 查询权限信息

      Collection<String> permissions = userService.findPermissions(user.getSystemuserid());

      info.addStringPermissions(permissions);

      log.info("shiro获取用户权限列表:"+permissions);

      return info;

     }

     

     @Override

     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException{

      //用户输入的用户名密码

      String loginname=  token.getPrincipal().toString();

      Object password=token.getCredentials();

      log.info("shiro正在处理尝试登录的用户信息:"+loginname+",密码:"+new String((char[])password));

      //数据库中的用户信息

      UserInfo user =userService.queryUserInfoByLoginName(loginname);

      if(user==null||CommonUtil.isNull(user.getLoginusername(),user.getPassword(),user.getSystemuserid())){

       return null;

      }

      log.info("shiro获取到当前用户尝试登录的真实数据:"+user.getLoginusername()+",密码:"+user.getPassword());

      //数据库中的正确的账户信息

      AuthenticationInfo accountInfo =new SimpleAuthenticationInfo(user, user.getPassword(),getName());

        

      //自己获取密码验证器(由于shiro实现的密码校验方法是密码错误会直接抛异常,不采用,所以改成直接手动校验)

      CredentialsMatcher matcher=getCredentialsMatcher();

      if(matcher==null){

       log.error("没有配置密码匹配器");

       return null;

      }

      //校验密码

      if(matcher.doCredentialsMatch(token,accountInfo)){

       return accountInfo;//校验通过,返回账号信息

      }

      

      return null;

     }

     

     

    }

  4. 自定义密码校验器


    /**

     * 自定义shiro密码匹配(密码是在md5散列值的基础上再次进行md5加盐操作,加盐值不保存在数据库,而是放在配置文件中)

     * @author eguid

     *

     */

    public class MyCredentialsMatcher extends CodecSupport implements CredentialsMatcher {

     private static final Logger log = LoggerFactory.getLogger(MyCredentialsMatcher.class);

     

     protected Object getCredentials(AuthenticationToken token) {

      return token.getCredentials();

     }

     

     protected Object getCredentials(AuthenticationInfo info) {

      return info.getCredentials();

     }

     

     @Autowired

     private CommonConfigs commonConfigs;

     /**

      * 验证密码

      *

      * @param tokenCredentials

      * @param accountCredentials

      * @return

      */

     protected boolean equals(Object tokenCredentials, Object accountCredentials) {

      if (log.isDebugEnabled()) {

       log.debug("Performing credentials equality check for tokenCredentials of type ["

         + tokenCredentials.getClass().getName() + " and accountCredentials of type ["

         + accountCredentials.getClass().getName() + "]");

      }

      if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) {

       if (log.isDebugEnabled()) {

        log.debug("Both credentials arguments can be easily converted to byte arrays.  Performing "

          + "array equals comparison");

       }

       byte[] tokenBytes = toBytes(tokenCredentials);

       byte[] accountBytes = toBytes(accountCredentials);

       return MessageDigest.isEqual(tokenBytes, accountBytes);

      } else {

       return accountCredentials.equals(tokenCredentials);

      }

     }

     

     public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

      Object tokenCredentials = getCredentials(token);

      Object accountCredentials = getCredentials(info);

      String account=String.valueOf((char[])tokenCredentials);

      if(commonConfigs.getMd5salt()==null){

       if (log.isDebugEnabled()) {

        log.debug("配置文件中的加盐值为空,无法进行密码匹配,请确认配置文件是否在指定位置或配置指定加盐值");

       }

       return false;

      }

      String saltaccount=MD5Util.getMD5(account, commonConfigs.getMd5salt());

      if (log.isDebugEnabled()) {

       log.debug("加盐后的密码:"+saltaccount);

      }

      return equals(accountCredentials, saltaccount.toCharArray());

     }

     

    }

  5. 注解使用及模板标签使用

    1、注解使用
    @RequiresPermissions({"user:update:view"})//检查操作权限
    @RequiresPermissions(value={"user:add","user:view"},logical=Logical.OR)//两个操作权限其中一个满足条件即可通过检查
    @RequiresRoles({"admin"})//检查角色
    @RequiresRoles(value={"debug","admin"},logical=Logical.OR)//两个角色其中一个角色满足条件即可

    @RequiresAuthentication//检查是否通过shiro认证
    @RequiresGuest//不需要验证
    @RequiresUser//检查用户是否是当前系统中的用户

    2、标签使用
    使用标签需要先导入shiro的标签库<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
    (1)显示用户身份信息
    <shiro: principal/>
    默认调用Subject.getPrincipal()获取

    <shiro:principal property="username"/>
    相当于((User)Subject.getPrincipals()).getUsername()

    (2)已登录shiro用户显示

     <shiro:user> 
    欢迎[<shiro:principal/>]登录,<a href="logout">退出</a> 
    <shiro:user>

    (3)匿名用户访问
    <shiro:guest>未经过shiro验证的用户(游客,匿名用户)</shiro:guest> 

    (4)已经在shiro登录过的(已登录用户)

     <shiro:authenticated> 
        用户[<shiro:principal/>]已身份验证通过 
    <shiro:authenticated>

    (5)没有在shiro登录过的


     <shiro:notAuthenticated>
        未身份验证(包括记住我)
    <shiro:notAuthenticated>

    (6)检查角色

     <shiro:hasRole name="admin">
        用户[<shiro:principal/>]拥有角色admin<br/>
    <shiro:hasRole>

    检查任意角色(其中一个满足条件即通过,相当于OR)
     <shiro:hasAnyRoles name="admin,user">
        用户[<shiro:principal/>]拥有角色admin或user<br/>
    <shiro:hasAnyRoles>

    不具有角色(反向判断)
     <shiro:lacksRole name="abc">
        用户[<shiro:principal/>]不具有角色abc<br/>
    <shiro:lacksRole>

    (7)操作权限判断

     <shiro:hasPermission name="user:create"> 
        用户[<shiro:principal/>]拥有权限user:create<br/> 
    <shiro:hasPermission>   

    不具有操作权限(反向判断)


     <shiro:lacksPermission name="org:create"> 
        用户[<shiro:principal/>]没有权限org:create<br/> 
    <iro:lacksPermission> 

    END
posted @ 2019-11-16 14:24  DiligentCoder  阅读(818)  评论(0编辑  收藏  举报