• 权限认证与授权(Shrio 框架)


    权限概述

    • 认证: 系统提供的用于识别用户身份的功能, 通常登录功能就是认证功能; -- 让系统知道你是谁
    • 授权: 系统授予用户可以访问哪些功能的证书. -- 让系统知道你能做什么!

    常见的权限控制方式

    • URL 拦截权限控制

      • 底层基于拦截器或过滤器实现
    • 方法注解权限控制

      • 我们框架会将加入注解的Action创建代理对象,由代理对象进行权限校验,如果校验通过,通过反射调用目标对象的方
        法,如果校验不通过,框架会抛出权限不足异常;
      • 底层基于代理技术实现,为 Action 创建代理对象,由代理对象进行权限校验;

    创建权限数据模型

    • 权限表
    • 角色表(权限的集合), 引入角色表,是为了方便授权
    • 用户表
    • 角色权限关系表
    • 用户角色关系表

    apache shiro 框架

    • 核心功能
      • 身份认证(Authentication): 简称"登录";
      • 授权(Authorization):给用户分配角色或者权限资源;
      • 会话管理(Session Management)
      • 加密

    shiro 框架认证流程

    1. 使用shiro框架的URL拦截进行权限控制(基于过滤器技术实现)

    1.1 导入jar包: shiro-all;

    1.2 在web.xml中配置一个由spring提供的过滤器,用于整合shiro框架(这个过滤器必须放在struts2 过滤器前)

    <!-- 配置spring 框架提供的用于整合shiro框架的过滤器 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    1.3 在spring配置文件中配置bean,id和上面的过滤器名称一致

    <!-- 配置shiro框架的过滤器工厂对象 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 注入安全管理器对象 -->
        <property name="securityManager" ref="securityManager"></property>
        <!-- 注入相关页面,访问URL -->
        <property name="loginUrl" value="/login.jsp"/>
        <property name="successUrl" value="/index.jsp"/>
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    
        <!-- 注入URL拦截规则 -->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon
                /js/** = anon
                /images/** = anon
                /validatecode.jsp* = anon
                /login.jsp = anon
                /userAction_login.action = anon
                /page_base_staff.action = perms["staff-list"]
                /* = authc
            </value>
        </property>
    </bean>
    
    <!-- 注册安全管理器对象 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="bosRealm"></property>
    </bean>
    
    <!-- 注册 realm -->
    <bean id="bosRealm" class="cn.itcast.bos.realm.BOSRealm"></bean>
    

    1.4 修改 UserAction 中的login方法,使用shiro框架提供的方式进行认证操作

    // UserAction.java
    public class UserAction extends BaseAction<User>{
    
        // 属性驱动,接收页面输入的验证码
        private String checkcode;
        public void setCheckcode(String checkcode){
            this.checkcode = checkcode;
        }
    
        // 使用shiro框架提供的方式,进行认证操作
        public String login(){
            // 从Session中获取生成的验证码
            String validatecode =
                    (String)ServletActionContext.getRequest().getSession().getAttribute("key");
            //校验验证码是否正确
            if(StringUtils.isNotBlank(checkcode) && checkcode.equals(validatecode)){
                // 使用shiro框架提供的方式进行认证操作
                Subject subject = SecurityUtils.getSubject(); // 获取当前用户对象
                // 创建用户名,密码令牌对象
                AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),
                                                        MD5Utils.md5(model.getPassword()));
                try{
                    subject.login(token);
                }catch(Exception e){
                    e.printStackTrace();
                    return LOGIN;
                }
                // 登录成功,将user从当前线程中取出,放入session中
                User user = (User)subject.getPrincipal();
                ServletActionContext.getRequest().getSession().setAttribute("loginUser",user);
                return HOME;
            }else{
                // 输入的验证码错误,设置提示信息,跳转到登录页面
                this.addActionError("输入的验证码错误!");
                return LOGIN;
            }
        }
    }
    
    // 自定义realm类, BOSRealm.java
    public class BOSRealm extends AuthorizingRealm{
    
        @Autowired
        private IUserDao userDao;
    
        // 认证方法
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
                                                            throws AuthenticationException {
            UsernamePasswordToken passwordToken = (UsernamePasswordToken)token;
            // 获取页面输入的用户名
            String username = passwordToken.getUsername();
    
            // 根据用户名查询数据库中的密码
            User user = userDao.findUserByUsername(username);
            if(user == null){
                // 如果页面输入的用户名不存在
                return null;
            }
            // 创建简单认证对象
            AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),
                                                                            this.getName());
            // shiro框架负责比对数据库中的密码和页面输入的密码是否一致
            return info;
        }
    
        // 授权方法
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            // 为用户授权
            info.addStringPermission("staff-list");
    
            // 获取当前用户(两种方式)
            User user1 = (User)SecurityUtils.getSubject().getPrincipal();
            User user2 = (User)principals.getPrimaryPrincipal();
    
             // TODO 获取需要修改为根据当前登录用户查询数据库,获取实际对应的权限
            return info;
        }
    }
    

    2. 使用 shiro 的方法注解方式进行权限控制(基于代理技术实现)

    2.1 在spring配置文件中开启shiro注解支持

    <!-- 开启shiro框架注解支持  -->
    <bean id="defaultAdvisorAutoProxyCreator"
            class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        <!-- 强制使用cglib,创建Action的代理对象 -->
        <property name="proxyTargetClass" value="true"/>
    </bean>
    
    <!-- 配置shiro框架提供的切面类,用于创建代理对象 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
    

    2.2 在Action类中的方法上,使用shiro框架提供的注解,@RequiresPermissions("权限名称")

    • 在权限不足时,会抛出如下异常:

    2.3 在 struts.xml 中配置全局异常捕获,当shiro框架抛出权限不足异常时,跳转到权限不足提示页面

    <!-- 配置全局结果集 -->
    <global-results>
        <result name="unauthorized">/unauthorized.jsp</result>
    </global-results>
    
    <!-- 配置全局异常处理 -->
    <global-exception-mappings>
        <exception-mapping result="unauthorized"
                                exception="org.apache.shiro.authz.UnauthorizedException"/>
    </global-exception-mappings>
    

    3. 使用shiro提供的页面标签方式进行权限控制

    3.1 在jsp页面中,引入shiro的标签库:

    • <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>

    3.2 使用shiro的标签控制页面元素的展示

    <shiro:hasPermission name="权限名称">
        <!-- 页面中需要权限控制的元素 -->
        <input type="button" value="test"/>
    </shiro:hasPermission>
    

    使用 ehcache 缓存权限数据

    1. 导入jar包: com.springsource.net.sf.ehcache

    2. 在项目中提供 ehcache 的配置文件

    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	               xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    
        <diskStore path="java.io.tmpdir"/>
    
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="true"
                maxElementsOnDisk="10000000"
                diskPersistent="false"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU"
                />
    </ehcache>
    

    3. 在spring配置文件中配置缓存管理器对象,并注入给安全管理器对象

    // applicationContext.xml
    
    <!-- 注册安全管理器对象 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="bosRealm"></property>
        <!-- 注入缓存管理器 -->
        <property name="cacheManager" ref="cacheManager"></property>
    </bean>
    
    <!-- 注入缓存管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <!-- 注入 ehcache 的配置文件 -->
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property>
    </bean>
    
  • 相关阅读:
    MFC-窗口指针
    MFC-EditControl文本控件(多行输入)一行一行读取
    MFC-文件对话框
    MFC-ToolBar工具栏
    MFC-CMenu菜单
    MFC-访问对话框控件的七种方法
    CC++:scanf的用法
    C/C++:printf的用法
    C/C++:创建第一个程序helloworld!
    NX二次开发-NX客户机与服务器FTP上传下载文件
  • 原文地址:https://www.cnblogs.com/linkworld/p/7883039.html
Copyright © 2020-2023  润新知