权限控制与Apache Shiro框架

权限控制的两种方式:

1. URL粗粒度的权限控制

   1. 原理: filter,拦截url,从session中获取用户,查看用户的权限
   2. 特点: 
      1.  只能拦截一次
      2. 一个filter可以对多个url进行拦截
      3. 一般用于基本的模块之间的权限控制,控制一些不太敏感的权限。

2. 方法注解细粒度权限控制

   1. 原理: 自定义注解,AOP面向切面编程
   2. 特点:
      1.  所有调用的方法都可以进行注解的控制,一次请求可以多次的控制
      2. 每一个权限的控制的方法都需要独立添加注解
      3. 一般用于敏感的权限操作,高权限控制

Shiro核心:
这里写图片描述
spring整合Shiro步骤:
1.添加依赖shiro-all:

<!-- 权限控制 框架 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>${shiro.version}</version>
        </dependency>

2.配置wab.xml文件中filter:

    <!-- shiro的Filter  -->
    <filter> 
        <!-- 去spring配置文件中寻找同名bean  -->
        <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>

ps:这里需要注意:
权限控制的filter一般配置在其他filter前面,拦截所有请求;
一般拦截所有的url:/*;
配置的filter的那么需要与spring配置中的bean的id一致,一般使用shiroFilter;
3.配置spring的配置文件:

<!-- 配置Shiro核心Filter  --> 
    <bean id="shiroFilter" 
        class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 安全管理器 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 未认证,跳转到哪个页面  -->
        <property name="loginUrl" value="/login.html" />
        <!-- 登录页面页面 -->
        <property name="successUrl" value="/index.html" />
        <!-- 认证后,没有权限跳转页面 -->
        <property name="unauthorizedUrl" value="/unauthorized.html" />
        <!-- shiro URL控制过滤器规则  -->
        <property name="filterChainDefinitions">
            <value>
                /login.html* = anon
                /user_login.action* = anon 
                <!--验证码 -->
                /validatecode.jsp* = anon
                /css/** = anon
                /js/** = anon
                /images/** = anon
                /services/** = anon 
                /pages/base/courier.html* = perms[courier:list]
                /pages/base/area.html* = roles[base]
                /** = authc
            </value>
        </property>
    </bean>

    <!-- 安全管理器  -->
    <bean id="securityManager" 
        class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="bosRealm" />
        <!-- <property name="cacheManager" ref="shiroCacheManager" /> -->
    </bean>

    <!-- 配置Realm -->
    <bean id="bosRealm" class="cn.itcast.bos.realm.BosRealm">
    </bean>

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

    <!-- 开启shiro注解模式  -->
    <bean
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor" >
        <!--代理类实现-->
        <property name="proxyTargetClass" value="true" />
    </bean>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
         <property name="securityManager" ref="securityManager"/>
    </bean>

ps需要注意:
1.过滤器的name必须和spring的id一致;
2. 注入依赖对象

     1. 安全管理器
     2. 未认证跳转的页面   loginUrl
     3. 未授权跳转的页面   unauthorizedUrl
     4. 需要认证才能访问的页面  successUrl
     5. url的拦截规则   filterChainDefinitions
        1. 一行写一个规则
        2. 从上到下匹配,第一个规则生效
        3. 规则的名称
           1. anon      认证和未认证都能访问
           2. authc      认证后可以访问
           3. logout     未认证可以访问
           4. perms     需要指定的权限
           5. roles        需要指定的角色

4.shiro认证的步骤:

  1. 在项目中创建UserAction,创建login方法

         2. 获取Subject subject = SecurityUtils.getSubject(); 对象

         3. 调用登录方法,传递token参数

            AuthenticationToken token = new UsernamePasswordToken(
                            model.getUsername(), model.getPassword());
            subject.login(token);

         4. 编写realm类,将realm注入到安全管理器中

         5. 继承AuthorizingRealm,编写认证的方法doGetAuthenticationInfo

         6. 根据token查询数据库中的user对象

            1. 如果没有查询到user对象,说明用户名不存在,直接返回 null

            2. 如果能够查询数据库的user对象,返回

               ```java
               // 参数一: 保存在session中的对象
               // 参数二: 数据库中的密码,安全管理器会和token中密码比对
               // 参数三: realm的名称,多认证的系统会用到
               new SimpleAuthenticationInfo(user, user.getPassword(),this.getName());
               ```

         7. 如何在Action中获取登录的结果

            通过异常处理机制来通知action的

                1. 没有任何异常,表示登录成功(token中的密码和realm中的第二个参数一致)
                2. 如果realm返回null,抛出 UnknownAccountException
                3. 如果密码不一致,抛出 IncorrectCredentialsException

5.shrio授权管理的步骤:

   1. 在spring配置文件中,设置权限控制。
         /pages/base/courier.html* = perms[courier:list]
         /pages/base/area.html* = roles[base]

      2. shiro框架在访问到指定权限或者角色的url的时候,就会自动的调用realm中的授权方法

      3. 在授权方法 doGetAuthorizationInfo中,通过以下代码进行授权,在方法中获取登录用户的信息

         //获取登录用户的信息
         Subject subject = SecurityUtils.getSubject();
         User user = (User) subject.getPrincipal();
         //授予角色
         authorizationInfo.addRole(role.getKeyword());
         //授予权限
         authorizationInfo.addStringPermission(permission.getKeyword());

认证与授权demo代码:

@Override
    // 授权...
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        System.out.println("shiro 授权管理...");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 根据当前登录用户 查询对应角色和权限
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        // 调用业务层,查询角色
        List<Role> roles = roleService.findByUser(user);
        for (Role role : roles) {
            //添加角色
            authorizationInfo.addRole(role.getKeyword());
        }
        // 调用业务层,查询权限
        List<Permission> permissions = permissionService.findByUser(user);
        for (Permission permission : permissions) {
            //添加权限
            authorizationInfo.addStringPermission(permission.getKeyword());
        }

        return authorizationInfo;
    }

    @Override
    // 认证...
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("shiro 认证管理... ");

        // 转换token
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        // 根据用户名 查询 用户信息
        User user = userService.findByUsername(usernamePasswordToken
                .getUsername());
        if (user == null) {
            // 用户名不存在
            // 参数一: 期望登录后,保存在Subject中信息
            // 参数二: 如果返回为null 说明用户不存在,报用户名
            // 参数三 :realm名称
            return null;
        } else {
            // 用户名存在
            // 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
            // 如果密码一致 登录成功, 如果密码不一致 报密码错误异常
            return new SimpleAuthenticationInfo(user, user.getPassword(),
                    getName());
        }

    }

6.校验规则:
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/caiyibing1992/article/details/82630950