ERP管理系统的权限控制实现--shiro

1 Shiro基本原理分析


Authentication身份认证/登录,验证用户是不是拥有相应的身份;

Authorization授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

Session Manager会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

Shiro可以使用的地方:命令行程序、移动应用、web项目、spring项目...

 

 

 

应用代码

----  访问Subject (shiro的Subject 就代表当前登陆用户)

 ---- Subject 在shiro框架内部自动调用 Shiro SecurityManager 安全管理器,shiro的核心(好比Struts2的核心控制器)

 ----- 安全管理器调用 Realm域 (程序员自定义的 )

可以看到:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject;其每个API的含义:

Subject主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

SecurityManager安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

Realm域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

 

也就是说对于我们而言,最简单的一个Shiro应用:

1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager进行处理;

2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的数据。

在这个过程中我们需要关注的问题:

1、 如何获取subject

2、 如何定义一个Realm域

3、 密码比较器如何编写

2、系统登录功能—Shiro与Spring整合

Shiro的使用不依赖Spring框架,javase可以用,javaee也可以用,移动应用程序可以用,大型的网络和企业应用程序也可以使用Shiro

 

传统登录方式:

Shiro安全框架实现登录

 

 

传统的方式是,客户端发出请求给Action,action接受用户的用户名和密码,然后由Action调用业务逻辑,在Action中调用Service,然后service负责调用数据库进行处理,如果用户名和密码正确,则将用户信息保存到session中,并且进入主页面

如果用户名和密码错误,则保存错误信息,然后将信息输出到客户端。

 

 

答:客户端发送请求到Action,action接受用户的用户名和密码,第一步还是一样的,但是第二步不一样了,以前第二步是Action直接调用Service处理,现在Action调用Shiro安全框架去处理,也就是说将认证授权抽取出来,有一个框架专门为你做认证做授权,这里有框架去帮我们完成认证和授权,然后告诉你这个用户名和密码是否可用还是不可用,当然此时,认证成功之后,只要从shiro中取出认证的结果,如果成功的话,将用户保存至session中,然后在跳转至jsp

这个过程相比于早期的操作,相当于验证用户名和密码的业务逻辑交给shiro安全框架来做。并且加密也交给shiro安全框架来做,然后由shiro安全框架来加密,由shiro拿密文与数据库中的密文进行比较。

 

总结一下:shiro就是一个安全框架,帮助我们解决认证、授权、加密和密码比较的过程。

 

 

2.1 shiro开发步骤

2.1.1 导入jar包

在jx_parent项目中,导入shiro的依赖jar包,具体配置如下:

<dependency>

             <groupId>org.apache.shiro</groupId>

             <artifactId>shiro-all</artifactId>

             <version>1.3.2</version>

</dependency>

 

2.1.2 过滤器的配置

Shiro怎么用呢?他能解决啥问题?认证、授权、会话管理、加密、与web集成、缓存这6块主要功能

认证:其实认证的方式有很多,可以刷脸、刷指纹,shiro主要借助于用户名和密码进行认证。

      Shiro能帮你做的就是根据用户名和密码进行认证

使用shiro,需要配置shiro框架。使用Shiro时,需要配置的相关权限过滤器如下(共10个):


认证和授权是两码事.

Anon可以不登陆访问;authc必须登录才能访问。

 

配置过滤器web.xml:一个过滤器代理类,配置shiroFilter后,可以应用 10种过滤规则

配置shiroFilter其实是一个过滤器链,含有10个Filter

<!-- Shiro Security filter  filter-name这个名字的值将来还会在spring中用到  -->

    <filter>

        <!-- 这里的 filter-name 要和 spring applicationContext-shiro.xml 里的 org.apache.shiro.spring.web.ShiroFilterFactoryBean bean name 相同 -->

        <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>

 

【注意】这个shiroFilter的配置一定要在struts2的控制器之前配置,否则shiroFilter无法启动

以前的web的过滤器谁初始化的?

Servlet容器初始化的。

 

这个Filter 是 spring提供的,DelegationFilterProxy 是代理Filter

(会自动找和<filter-name> 同名的 <bean> 对象)

 

2.1.3 shiro标签

什么时候调用授权的方法:主要看页面是否有shiro标签 

<shiro:notAuthenticated><inputtype=”button” value=”登录”></shiro:notAuthenticated>

<shiro:authenticated><input type=”button”value=”注销”></shiro:authenticated>

 

<c:if test=””>

 

 Home文件下下面的title页面就使用了这个标签,具体如下,也可以进入页面查看:

 


2.1.4 Shiro的配置文件

配置applicationContext-shiro.xml:(shiro权限控制过滤器+shiro安全管理器):

applicationContext-shiro.xml放置的位置:

 

shiro的配置步骤 -->

1 配置安全管理器SecurityManager

2 realm域配置:由于SecurityManger需要使用realm,涉及到用户信息、权限信息,处理用户信息的时候需要加密

3 密码比较器:用户输入的铭文进行加密,并且与数据库中的密文进行比较

4 配置生成过滤器的工厂类

5 整个过程中,用户的数据都放入了realm、域中了,那么下次用户访问的时候,还需要查吗?

          如果没有缓存,那还需要查,所以这里需要配置缓存,采用ehcache作为缓存提供商

在该文件中需要配置的内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" 

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      

    xmlns:p="http://www.springframework.org/schema/p" 

    xmlns:context="http://www.springframework.org/schema/context"  

    xmlns:tx="http://www.springframework.org/schema/tx" 

    xmlns:aop="http://www.springframework.org/schema/aop" 

    xsi:schemaLocation="http://www.springframework.org/schema/beans   

    http://www.springframework.org/schema/beans/spring-beans.xsd   

    http://www.springframework.org/schema/aop   

    http://www.springframework.org/schema/aop/spring-aop.xsd   

    http://www.springframework.org/schema/tx   

    http://www.springframework.org/schema/tx/spring-tx.xsd   

    http://www.springframework.org/schema/context   

    http://www.springframework.org/schema/context/spring-context.xsd">

   

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

   

    <!-- 调用Realm -->

    <!-- realm与调用密码比较器 -->

    <!-- 缓存 -->

    <!-- 配置具体的过滤规则 -->

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

        <!-- Single realm app.  If you have multiple realms, use the 'realms' property instead. -->

        <property name="realm" ref="authRealm"/><!-- 引用自定义的realm -->

        <!-- 缓存 -->

        <property name="cacheManager" ref="shiroEhcacheManager"/>

    </bean>

 

    <!-- 自定义权限认证 -->

    <bean id="authRealm" class="cn.itcast.jx.shiro.AuthRealm">

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

        <!-- 自定义密码加密算法  -->

        <property name="credentialsMatcher" ref="passwordMatcher"/>

    </bean>

   

    <!-- 设置密码加密策略 md5hash -->

    <bean id="passwordMatcher" class="cn.itcast.jx.shiro.CustomCredentialsMatcher"/>

 

    <!-- filter-name这个名字的值来自于web.xmlfilter的名字 -->

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

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

        <!--登录页面  -->

        <property name="loginUrl" value="/index.jsp"></property>

        <!-- 登录成功后 -->     

        <property name="successUrl" value="/home.action"></property>

       

        <property name="filterChainDefinitions">

            <!-- /**代表下面的多级目录也过滤 -->

            <value>

                /index.jsp* = anon

                /home* = anon

                /sysadmin/login/login.jsp* = anon

                /sysadmin/login/logout.jsp* = anon

                /login* = anon

                /logout* = anon

                /components/** = anon

                /css/** = anon

                /images/** = anon

                /js/** = anon

                /make/** = anon

                /skin/** = anon

                /stat/** = anon

                /ufiles/** = anon

                /validator/** = anon

                /resource/** = anon

                /** = authc

                /*.* = authc

            </value>

        </property>

    </bean>

 

    <!-- 用户授权/认证信息Cache, 采用EhCache  缓存 -->

    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">

        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>

    </bean>

 

    <!-- 开启权限控制的注解功能 -->

    <!-- 后处理器:通过动态代理在某bean实例化的前增强。 -->

    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->

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

   

    <!-- 生成代理,通过代理进行控制 :切面自动代理:相当于以前的AOP标签配置-->

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"

          depends-on="lifecycleBeanPostProcessor">

        <property name="proxyTargetClass" value="true"/>

    </bean>

   

    <!-- 注入安全管理器:Advisor切面配置:授权属性的切面 -->

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

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

    </bean>

   

</beans>

 

2.1.5 在applicationContext.xml文件中加载shiro配置文件

<import resource="classpath:spring/applicationContext-shiro.xml"></import>


2.1.6 配置ehcache-shiro.xml文件

直接拷贝文件

 


2.1.7准备Realm域和密码比较器

1 创建AuthRealm类,继承AuthorizingRealm

package cn.itcast.jx.shiro;

 

import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.AuthenticationInfo;

import org.apache.shiro.authc.AuthenticationToken;

import org.apache.shiro.authz.AuthorizationInfo;

import org.apache.shiro.realm.AuthorizingRealm;

import org.apache.shiro.subject.PrincipalCollection;

import cn.itcast.jx.service.UserService;

/**

 * 自定义的Realm

 */

public class AuthRealm extends AuthorizingRealm {

      private UserService userService;

      public void setUserService(UserService userService) {

           this.userService = userService;

      }

      @Override

      protected AuthenticationInfo doGetAuthenticationInfo(

                 AuthenticationToken arg0) throws AuthenticationException {

           // 认证

          

           return null;

      }

      @Override

      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {

           // 授权

          

           return null;

      }

     

}

 

 

2 创建密码比较器类CustomCredentialsMatcher,继承SimpleCredentialsMatcher父类。

3 运行:观察结果,不进入登录页面,所以修改LoginAction

 

2.1.8 MD5加密介绍--shiro内部的加密

散列算法一般用于生成数据的摘要信息,是一种不可逆的算法一般适合存储密码之类的数据

常见的散列算法如MD5SHA等。一般进行散列时最好提供一个salt(盐),比如123456,,撒一把salt,salt是“admin”,

         产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,

         可以到一些md5解密网站很容易的通过散列值得到密码“admin”,

         即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,

         如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。

在工具包jx_util中加入Encrypt工具类,类中代码如下:

package cn.itcast.jx.util;

 

import org.apache.shiro.crypto.hash.Md5Hash;

/**

 * @Description:

 * @Author:         tengyuan

 * @Company:        http://java.itcast.cn

 */

public class Encrypt {

    /*

     * 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,

     * 常见的散列算法如MD5SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,

     * 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,

     * 可以到一些md5解密网站很容易的通过散列值得到密码“admin”,

     * 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,

     * 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。

     */

    //高强度加密算法,不可逆

    public static String md5(String password, String salt){

        /**

         * 第一个参数:密码

         * 第二个参数:盐

         * 第三个参数:打乱的次数

         */

        return new Md5Hash(password,salt,2).toString();

    }

    public static void main(String[] args) {

        /**

         * "123456","tony",1 5c51b703b1399a874e12d38a4cf33e46

         * "123456","tony",2 4eaf863bbc05d88cf4004f7a2da7877f

         * "123456","tony",3 d63664690a5dad12012b6e63a86e1d49

         * "123456","KMNO4",38bd35dc14dc07f756478bb44513694f6

         * 1 密码明文

         * 2

         * 3 几把

         */

        System.out.println(new Md5Hash("123456","KMNO4",3).toString());

       

        /**

         *Sha1Hash("123456", "tony", 1):1e88f1b63745c7aad14b74c28c09e29a9548e57b

         *

         */

        System.out.println(new Sha1Hash("123456", "tony", 1));

       

        System.out.println(new Sha256Hash("tony", "tony", 1));

       

        System.out.println(new Sha512Hash("123456", "tony", 1));

       

        System.out.println(new Sha384Hash("123456", "tony", 1));    }

}

2.1.9 编写密码比较器

在jx_web模块中,编写密码比较器类,类名为CustomCredentialsMatcher,这个类需要继承SimpleCredentialsMatcher父类。

具体代码如下:

package cn.itcast.jx.shiro;

 

import org.apache.shiro.authc.AuthenticationInfo;

import org.apache.shiro.authc.AuthenticationToken;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;

 

import cn.itcast.jx.util.Encrypt;

 

/**

 * @Description:

 * @Author:     刘腾远

 * @Company:    http://java.itcast.cn

 * @CreateDate: 20141230

 */

public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {

    /**

     * Authentication:认证

     * 重写SimpleCredentialsMatcher类的doCredentialsMatch(密码比较的方法)

     * 返回true:校验成功

     * 返回false:校验失败

     *

     * 第一个参数:AuthenticationToken:用户在界面上输入的用户名和密码,思考问题:页面如何传递过来?

     * 第二个参数:AuthenticationInfo:数据库中用户的密文    *

     */

    public boolean doCredentialsMatch(AuthenticationToken token,

            AuthenticationInfo info) {

        //向下转型

        UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        //2 得到原始密码

         //错误的方式

        //String oldPwd = upToken.getPassword().toString();

         //正确的方式

        String oldPwd = new String(upToken.getPassword());

         // 3 对密码进行加密

        String newPwd = Encrypt.md5(oldPwd, upToken.getUsername());

        // 获取数据库中的当前用户的密文

        Object dbPwd = info.getCredentials();

        //将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false 

        return equals(newPwd, dbPwd); 

    }

}

 

其实我们在applicationContext-shiro.xml中已经配置了密码校验器的代码(此时不需要配置了),具体配置如下:

<!-- 自定义加密策略 -->

<bean id="passwordMatcher" class="cn.itcast.jx.shiro.CustomCredentialsMatcher"/>

4.1.10 编写自定义的Realm域

【第一步】在jx_web中的shiro包中,创建AuthRalm类。

【第二步】类中编写认证的方法,代码如下:

public class AuthRealm extends AuthorizingRealm{

    private UserService userService;

    public void setUserService(UserService userService) {

        this.userService = userService;

    }

   

/**

     * 认证  登录

     * 当用户登录的时候,shiro真正会调用它,来实现登录操作

     *

     * 当这个方法返回null时,就会出现异常

     * 当认证成功后,返回的对象不为null时,就会自动进入密码比较器(在shiroxml文件中,配置了密码比较器)

     * <property name="credentialsMatcher" ref="passwordMatcher"/>

     *

     * 第一个参数:AuthenticationToken token:用户在页面输入的用户名和密码

     *

     */

    protected AuthenticationInfo doGetAuthenticationInfo(

            AuthenticationToken token) throws AuthenticationException {

        System.out.println("认证");

        // 1 向下转型

        UsernamePasswordToken upToken = (UsernamePasswordToken)token;

        // 2 根据用户名到数据库查找用户是否存在

        User user = userService.findUserByName(upToken.getUsername());

        // 3 判断用户对象是否存在,

        if(user==null){

            //用户名不存在

            return null;

        }else{

            //用户名存在

            // 将用户信息封装到AuthenticationInfo对象中,回头再密码比较器中需要调用

            /**

             * 第一个参数:Object principal:当前用户对象

             * 第二个参数:Object credentials:数据库中的密文

             * 第三个参数:String realmName:普通字符串,realm的名字,this.getName():当前类名对应的完整的包路径

             *

             */

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

            return info;

        }

    }  

}

 

在UserService中添加findUserByName方法,代码如下:

public abstract User findUserByName(String username);

 

在UserServiceImpl中实现findUserByName方法,代码如下:

public User findUserByName(String username) {

        List<User> list = baseDao.find("from User where userName = ?", User.class, new String[]{username});

        if(list!=null && list.size()>0){

            return list.get(0);

        }

        else {

            return null;

        }

    }

 

 

【第三步】编写授权的方法

     /**

      * 授权的方法

      * 使用的地方:当页面使用Shiro标签时,就会调用授权方法

      * (怎么调用?谁调用?由shiro的核心控制器调用)

      * 第一个参数:PrincipalCollection principals集合,对象主体集合

      *

      * 如何授权?答:根据当前用户的信息来获取当前用户对应的角色,判断这些角色具备的访问某些模块的权限,从而给予当前用户特定的权限

      * 所以授权第一步:获取当前用户

      *

      *

      */

     /**

     * PrincipalCollection principals:当前登录用户的集合

     *

     * AuthorizationInfo返回值:授权信息

     */

    protected AuthorizationInfo doGetAuthorizationInfo(

           PrincipalCollection principals) {

       // 授权

       //1 获取当前登录用户

       //方式一

       //User user = (User) principals.fromRealm(this.getName()).iterator().next();

       //方式二

       //User user2 = (User) ServletActionContext.getRequest().getSession().getAttribute(SysConstant.CURRENT_USER_INFO);

       //方式三

       User user = (User) SecurityUtils.getSubject().getPrincipal();

      

       //定义一个集合,用来接收用户权限的模块名字

       List<String> list = new ArrayList<String>();

      

       //获取用户的角色

       Set<Role> roles = user.getRoles();

       for(Role r:roles){

           //根据角色获取模块

           Set<Module> modules = r.getModules();

           //遍历模块

           for(Module m:modules){

              //判断是否是一级菜单,{系统首页,货物管理,系统管理}

              if(m.getCtype()==0){

                  list.add(m.getCpermission());

              }

           }

       }

       //list封装到AuthorizationInfo

       SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

       //

       info.addStringPermissions(list);

       return info;

    }

 

2.2用户登录

用户登录的代码如下:

//SSH传统登录方式

    public String login() throws Exception {       

        if(UtilFuns.isEmpty(username)){

            return LOGIN;

        }

        try {

            //shiro认证过程

            //1 获取Subject对象

            Subject subject = SecurityUtils.getSubject();

            //2 实现登录过程:封装用户在页面上提交的用户名和密码

            //就会进入Realm域中的认证方法

            UsernamePasswordToken token = new UsernamePasswordToken(username, password);

            //3将封装好的用户名和密码交给shiro安全框架并实现登录

            subject.login(token);

            //4 当认证成功后,要将Shiro中保存的用户对象取出来

            User principal = (User) subject.getPrincipal();

            //5 将用户对象放入session域中

            session.put(SysConstant.CURRENT_USER_INFO, principal);

//ServletActionContext.getRequest().getSession().setAttribute(SysConstant.CURRENT_USER_INFO, user);

        } catch (Exception e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

            request.put("errorInfo","对不起,登录失败,用户名或者面错误");

            return LOGIN;

        }

        // 6 跳页面

        return SUCCESS;

    }

 

【错误】此时抛出错误no session...,由于页面需要使用session,而此时session已经关闭了,主要原因是hibernate4.x开始,需要配置如下配置,方能继续使用session

<!-- 懒加载,配合web.xml中配置的 openSessionInViewFilter -->

<property name="hibernate.enable_lazy_load_no_trans">true</property>

 

 

 

 

 

2.3 Shrio的运行原理

 


  2.4 账户不存在的时候报错


【解决方案】

 

2.5 重复登录的bug

当登录成功之后,每次在页面输入如下地址的时候,还是会再次进入登录页面:


进入登录页面,需要重新登录:

【原因分析】为什么会进入登录页面?

答:


【解决方案】如何解决问题呢?

实现方式一:可以提前通过subject获取用户的信息,如果用户信息存在,直接跳转至success页面



实现方式二:shiro的subject提供了是否登录的方法isAuthenticated


实现方式三:获取session中的信息,判断是否登录了

 

2.6、注销功能的实现

【第一步】页面分析

点击按钮,请求的方法如下:

【第二步】在LoginAction中添加如下方法:


【第三步】在struts.xml中置Action

 

3、Shiro开发总结

开发步骤:

1.  使用maven坐标引入shiro的jar:

 

2.  Spring整合Shiro

Web.xml配置:DelgatingFilterProxy(spring的过滤器代理)

ApplicationContext-shiro.xml配置:提供filter同名的bean,该bean需配置安全管理器SecurityManager(DefaultWebSecurityManager基于HttpSession),还可以配置URL过滤规则等。

 

3.  程序调用Subject,Subject会自动调用SecurityManager,SecurityManager又会自动调用Realm,Realm域调用密码比较器,我们可以自定义Realm来实现安全数据和权限的结合。

 

4.  自定义Realm实现认证和授权。

 

5. Realm域调用密码比较器

 

6. 密码比较器调用加密算法

特点:

Shiro只是一个权限框架,数据(用户、角色、权限)可以来自与任何的的源,通过Realm获取源数据。

 

 

 

重点和总结:

1、    Shiro权限控制好处,为什么要使用Apache Shiro ?

使用简单,灵活数据可以采用自定义Realm 连接安全数据(没有数据来源要求, 来自文件、 数据库、网络 … )

          2、 Shiro 运行原理

应用代码 ---- Subject  ---SecurityManager  ----- Realm

          3、 自定义Realm 实现 用户认证和授权

          4、 Spring 整合 Shiro 进行 权限控制

        

 

代码部分:

         Shiro 会配置,会修改(不需要去记忆

n  Subject 代码调用

n  自定义Realm

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值