Shiro学习笔记(二)Shiro实现用户授权及简单整合springboot

Shiro学习笔记(二)Shiro实现用户授权及简单整合springboot

授权

授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限时无法访问的。

授权流程

  1. 系统调用subject相关方法将用户信息(例如isPermitted)递交给SecurityManager。
  2. SecurityManager将权限检测操作委托给Authorizer对象。
  3. Authorizer将用户信息委托给realm。
  4. Realm访问数据库获取用户权限信息并封装。
  5. Authorizer对用户授权信息进行判定。

授权方式

  • 基于角色的访问控制

    • RBAC基于角色的访问能控制(Role-Based Access Control)是以角色为中心进行访问控制

    • if(Subject.hasRole("admin")){
          //操作什么资源
      }
      
  • 基于资源的访问控制

    • RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制。

    • if(subject.isPermission("user:update:01")){
      	//对01用户进行修改
      }
      if(subject.isPermission("user:update:*")){
      	//可以对用户进行修改
      }
      

权限字符串

权限字符串规则:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源、操作、实例的分隔符,权限字符串也可以使用*通配符。

例子:

  • 用户创建权限:user:create,或user:create:*
  • 用户修改实例001的权限:user:update:001
  • 用户实例001的所有权限:user:*:001

Shiro中授权的实现方式

  • 编程式

    • Subject subject = SecurityUtils.getSubject();
      if(subject.hasRole("adming")){
          //有权限
      }else{
          //没有权限
      }
      
  • 注解式

    • @RequiresRoles("admin")
      public void hello(){
          
      }
      
  • 标签式

    • JSP/GSP 标签:在JSP/GSP页面进行相应的标签完成:
          <shiro:hasRole name="admin">
              <!- 有权限 ->
          </shiro:hasRole>
          注意:Thymeleaf 中使用shiro需要额外集成
      

开发授权

realm实现

package com.lany.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * @Description 使用自定义realm 加入md5+salt+hash
 * @Author 十里
 * @Date 2021/4/22 21:01
 */
public class CustomerMd5Realm extends AuthorizingRealm {
    /**
     * @Description 授权
     * @Author 十里
     * @Date 2021/4/22 20:59
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        System.out.println("身份信息:" + primaryPrincipal);

        //根据身份信息 用户名 获取当前用户的角色信息,以及权限信息 zhangsan admin user

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        //将数据库中查询角色信息复制给权限对象
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");

        //将数据库中查询权限信息赋值给权限对象
        simpleAuthorizationInfo.addStringPermission("user:*:01");
        simpleAuthorizationInfo.addStringPermission("product:create");


        return simpleAuthorizationInfo;
    }

    /**
     * @Description 认证
     * @Author 十里
     * @Date 2021/4/22 20:59
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取身份信息
        String principal = (String) token.getPrincipal();
        //根据用户名查询数据库

        if ("zhangsan".equals(principal)) {
            //参数1:数据库用户名,参数2:数据库md5+Salt之后的密码 参数3:注册时的随机盐 参数4:realm的名字
            return new SimpleAuthenticationInfo(principal,
                    "0e2cc6db0f430296bac325822f99bb62",
                    ByteSource.Util.bytes("X0*ps"),
                    this.getName());
        }
        return null;
    }
}

授权

package com.lany;

import com.lany.realm.CustomerMd5Realm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

import java.util.Arrays;

/**
 * @author 十里
 * @date 2021年04月22日 21:02
 */
public class TestCustomerMd5RealmAuthenticator {
    public static void main(String[] args) {
        //创建安全管理器
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //注入realm
        CustomerMd5Realm realm = new CustomerMd5Realm();
        //设置realm使用hash凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(credentialsMatcher);
        defaultSecurityManager.setRealm(realm);
        //将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过安全工具类获取subject
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");
        try {
            subject.login(token);
            System.out.println("登录成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }

        //认证用户进行授权
        if (subject.isAuthenticated()) {

            //1.基于角色权限控制
            System.out.println(subject.hasRole("user"));

            System.out.println("===============");
            //基于多角色权限认证
            System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));

            System.out.println("===============");
            //是否具有其中一个角色
            boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "super", "user"));
            for (boolean aBoolean : booleans) {
                System.out.println(aBoolean);
            }

            System.out.println("===============");

            //基于权限字符串的访问控制 资源标识符:操作:资源类型
            System.out.println("权限:" + subject.isPermitted("user:update:01"));
            System.out.println("权限:" + subject.isPermitted("product:create"));

            System.out.println("===============");
            //分别具有那些权限
            boolean[] permitted = subject.isPermitted("user:*:01", "product:create");
            for (boolean b : permitted) {
                System.out.println(b);
            }
            System.out.println("===============");

            //同时具有那些权限
            System.out.println(subject.isPermittedAll("user:*:01", "product:create"));


        }
    }
}

整合SpringBoot项目实战

整合思路
在这里插入图片描述

  • 创建springboot项目

  • 引入依赖

    • <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring-boot-starter</artifactId>
        <version>1.5.3</version>
      </dependency>
      
  • 配置shiro环境

    • 创建配置类

      • @Configuration
        public class ShiroConfig{
            //创建ShiroFilter
            @Bean
            public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){}
            
            //创建web管理器
            @Bean
            public DefaultWebSecurityManager getDefaultSecurityManager(Realm realm){}
            
            //创建自定义realm
            @Bean
            public Realm getRealm(){}
        }
        
        
    • 配置ShiroFilterFactoryBean

      • /**
             * 1.创建shiroFIlter    负责拦截所有请求
             *
             * @return
             */
            @Bean
            public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        
                ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
                //给filter设置安全管理器
                shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        
                //配置系统首先资源
                //配置系统公共资源
                HashMap<String, String> map = new HashMap<>();
                map.put("/user/login", "anon");//anon 设置为公共资源
                map.put("/**", "authc");// authc 请求这个资源需要认证和授权
        
                shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        
                //默认认证界面路径
                shiroFilterFactoryBean.setLoginUrl("/login.jsp");
        
                return shiroFilterFactoryBean;
            }
        
        
    • 配置WebSecurityManager

      • /**
             * 2.创建安全管理器
             *
             * @return
             */
            @Bean
            public DefaultWebSecurityManager getDefaultSecurityManager(Realm realm) {
        
                DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
                //给安全管理器设置realm
                defaultWebSecurityManager.setRealm(realm);
        
                return defaultWebSecurityManager;
            }
        
        
      • 这里配置的是DefaultWebSecurityManager,而不是DefaultSecurityManager,因为现在是web开发,所以需要使用DefaultWebSecurityManager,如果使用错安全管理器,会报错。

    • 创建自定义Realm

      •  /**
             * 3.创建自定义Realm
             *
             * @return
             */
            @Bean
            public Realm getRealm() {
        
                CustomerRealm customerRealm = new CustomerRealm();
        
                return customerRealm;
            }
        
        
      • package com.lany.springboot_jsp_shiro.shiro.realms;
        
        import org.apache.shiro.authc.AuthenticationException;
        import org.apache.shiro.authc.AuthenticationInfo;
        import org.apache.shiro.authc.AuthenticationToken;
        import org.apache.shiro.authc.SimpleAuthenticationInfo;
        import org.apache.shiro.authz.AuthorizationInfo;
        import org.apache.shiro.realm.AuthorizingRealm;
        import org.apache.shiro.subject.PrincipalCollection;
        
        /**
         * @author 十里
         * @description
         * @date 2021年04月23日 15:55
         */
        public class CustomerRealm extends AuthorizingRealm {
            /**
             * 授权
             *
             * @param principals
             * @return
             */
            @Override
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
                return null;
            }
        
            /**
             * 认证
             *
             * @param token
             * @return
             * @throws AuthenticationException
             */
            @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
                System.out.println("===============================");
                String principal = (String) token.getPrincipal();
        
                if ("xiaochen".equals(principal)) {
                    return new SimpleAuthenticationInfo(principal, "123", this.getName());
        
                }
                return null;
            }
        }
        
        
    • 首页及登录页

      • <%@page contentType="text/html; utf-8" pageEncoding="utf-8" isELIgnored="false" %>
        <!doctype html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport"
                  content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
        <h1>系统主页v1.0</h1>
        <a href="${pageContext.request.contextPath}/user/logout">退出登录</a>
        <ul>
            <li><a href="">用户管理</a></li>
            <li><a href="">商品管理</a></li>
            <li><a href="">订单管理</a></li>
            <li><a href="">物流管理</a></li>
        </ul>
        </body>
        </html>
        
      • <%@page contentType="text/html; utf-8" pageEncoding="utf-8" isELIgnored="false" %>
        <!doctype html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport"
                  content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
        <h1>用户登录</h1>
        <form action="${pageContext.request.contextPath}/user/login" method="post">
            用户名:<input type="text" name="username"/> <br/>
            密码:<input type="password" name="password"/> <br/>
            <input type="submit" value="登录"/>
        </form>
        </body>
        </html>
        
    • 因为项目中都以加入了权限控制以及用户认证,同时实现了用户退出登录功能。

    • demo中的用户权限及数据均为自定义的,未从数据库中获取,后面会编写整合mybatis的demo。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值