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

2023-10-27

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ERP管理系统的权限控制实现--shiro 的相关文章

  • 使用 Github for Windows 通过 SSH 处理自己的私有 Git

    现在 我正在使用 msysgit 来使用 SSH 来处理存储在 ec2 Amazon 云服务器上的我自己的私有存储库 到目前为止 我已经能够通过 Git Bash 成功连接到这些存储库 使用 ssh keygen 创建 ssh rsa 公钥
  • 如何解决22端口连接超时问题

    ssh connect to host bitbucket org port 22 Connection timed out fatal Could not read from remote repository Please make s
  • ssh:无法确定主机“主机名”的真实性

    当我 ssh 到一台机器时 有时我会收到此错误警告 并提示说 是 或 否 当从自动 ssh 到其他机器的脚本运行时 这会导致一些问题 警告信息 The authenticity of host
  • 我可以在远程服务器上运行位于本地计算机上的 bash 脚本吗?

    我有本地脚本 我想在远程服务器上运行 我已经设置了 ssh 密钥对以启用无需密码的登录 我当前的方法是将脚本 rsync 到服务器 然后运行它 ssh user remoteserver rsync localserver script s
  • 通过私钥使用 Python 进行 SSH

    在我的脚本中 我需要使用私钥通过 SSH 连接到远程系统 并将文件转储到其目录中 我用来 SSH 进入系统的命令是这样的 ssh i private key localhost 接下来是标准输入 输入密钥 private key 的密码 我
  • 如何将 Mercurial 存储库克隆到已存在的目录中?

    我有一个客户的 Django 项目 正在本地开发 使用 Mercurial 进行版本控制 我将本地存储库推送到我的个人远程服务器 我保存所有项目的地方 然后当我部署它时 在任何 Web 服务器上 我从我的个人服务器克隆该存储库 这在大多数服
  • 为什么 ssh-agent 需要 root 访问权限?

    我刚刚安装了 Archbang 并尝试克隆我的 Git 项目 这需要 SSH 密钥 过去 我在 Ubuntu 和 RedHat 机器上遵循 Github 指南取得了成功 但由于某种原因 它在我的新 Arch 安装上不起作用 我已使用以下命令
  • 如何让SSH命令执行超时

    我有一个这样的程序 ssh q email protected cdn cgi l email protection exit echo output value gt 在上面的代码中 我尝试通过 SSH 连接到远程服务器 并尝试检查是否可
  • 健全性检查 SSH 公钥? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我已要求用户提供他们的公共 id rsa pub ssh 密钥 然后将其放入 home theiraccount ssh authorized key
  • 安全地记住 bash 脚本中的 ssh 凭据[重复]

    这个问题在这里已经有答案了 假设我有一个 bash 脚本 它通过 ssh 在远程计算机上执行命令 Do something here ssh otheruser host command1 Do something else ssh oth
  • 无法通过 SSH 连接到 EC2 实例

    因此 我从网上启动了我的实例 下载了密钥对并安装了它 大约一天的时间里一切都运行良好 然后我重新启动了计算机 但我无法再通过 SSH 连接到它 我尝试重新下载密钥对并重新安装它 但我不断收到 权限被拒绝 公钥 错误 这是详细的输出 我也尝试
  • 允许 Kubernetes 用户列表/获取命名空间

    我有以下用户清单 我希望允许 myapp user 获取集群内所有命名空间的列表 根据我的查找 我应该创建一个 ClusterRole 但我无法真正找到足够的详细信息 是否有所有 apiGroup 以及相应资源和动词的列表 apiVersi
  • 伪分布式模式下的 Hadoop。连接被拒绝

    P S 请不要将此标记为重复 Hi 我一直在尝试以伪分布式模式设置和运行 Hadoop 当我运行 start all sh 脚本时 我得到以下输出 starting namenode logging to home raveesh Hado
  • SSH 到 Openshift 服务器失败

    我正在 openshift 服务器上使用 jboss catridge 我希望与其他人共享此实例并添加其他用户的公钥 id rsa pub 当其他人尝试访问该实例时 他会收到以下错误 我在他的实例中尝试了同样的方法 但看到了同样的错误 与
  • Composer 用于下载私有 GitHub 存储库

    我无法使用 Composer 下载 github 私人存储库 php composer phar update 我收到以下错误 The https api github com repos company private1 https ap
  • Ansible bitbucket 克隆存储库配置 ssh 错误

    我之前发布过这个问题 但那里的答案不再有效 总之 当使用 Ansible 配置我的 vagrant box 时 在尝试使用 ssh 克隆我的 bitbucket 私有存储库时 我遇到了一个神秘的错误 该错误指出 权限被拒绝 公钥 然而 如果
  • 连接到 OpenShift (Redhat Paas) mysql 实例

    我正在尝试将我的 C 应用程序与 openshift 数据库连接 但我得到了这个例外conn Open Eccezione gt MySql Data MySqlClient MySqlException 0x80004005 Unable
  • 无法通过 Python 子进程进行 SSH

    我需要通过堡垒 ssh 进入机器 因此 该命令相当长 ssh i
  • 如何使用ssh直接连接远程docker容器

    我想直接使用 ssh 连接到远程运行的 Docker 容器 通常我可以 ssh i privateKey user host docker ps which will list all running containers docker e
  • ssh:连接到主机 bitbucket.org 端口 22:连接超时

    一切都工作得很好 做了一些git pushes 没有问题 今天我决定将我的框架更新到最新版本 因此它稍微改变了我项目的目录结构 因此 在 Bitbucket 中 我创建了一个新的存储库 dev1 project com 并将我的项目文件夹重

随机推荐

  • JAVA学习【2】错误:无法从静态上下文中引用非静态

    编程时遇到 错误 无法从静态上下文中引用非静态 输出10到20的数字 程序如下 public class MyCode1 int count 10 public static void main String args while coun
  • 顺序表的实现与基本操作

    1 顺序表定义 1 1 顺序表定义 静态分配 c语言实现 include
  • sqli-labs 5~6 多命通关攻略

    sqli labs 5 6 多命通关攻略 描述 判断注入类型 正常输入 不正常输入 错误输入 判断 SQL 查询结果的列数 猜测 SQL 查询结果中的列数为两列 猜测 SQL 查询结果中的列数为三列 猜测 SQL 查询结果中的列数为四列 爆
  • 全面了解虚幻引擎 5

    Incredibuild 与 Epic 合作密切 并与虚幻引擎深度集成 因此对于虚幻引擎 5 的发布 我们也是既期待又兴奋 不得不说 虚幻引擎 5 没有辜负我们的期待 在技术上达到了真正的 虚幻 级别 虚幻引擎 4 的进步本身也不少 公正地
  • Python---Anaconda安装

    目录 前言 Anaconda介绍 特点 一 下载安装包 1 1 官网直接下载 1 2 清华镜像网下载 二 安装 三 配置 3 1 配置环境变量 3 2 验证安装 anaconda验证 python版本验证 3 3 anaconda设置 更改
  • 故障分析

    作者 刘晨 网名 bisal 具有十年以上的应用运维工作经验 目前主要从事数据库应用研发能力提升和技术管理相关的工作 Oracle ACE 腾讯云TVP 拥有 Oracle OCM OCP EXIN DevOps Master SCJP 等
  • VUE加解密MD5、RSA(分段)、AES(SHA1PRNG)

    md5方法 使用 crypto js 1 安装 npm install crypto js 2 引用 import CryptoJS from crypto js 3 加密 let md5 CryptoJS MD5 test toStrin
  • k8s 1.26.3 安装--使用containerd

    机器准备 或虚拟机 三台机器 一 环境准备 1 三台机器分别设置主机名 hostnamectl set hostname master hostnamectl set hostname node2 hostnamectl set hostn
  • 05-----Qt应用程序在windows和Linux操作系统下的打包发布

    1 介绍 对于发布程序 我们最常用的就是获取release版本的exe后 拷贝对应的动态库然后发布 但是QT下我们可以使用相关软件代替 它能帮我们找到该exe所需的动态库文件 下面我们直接参考以下文章即可 非常详细 很不错 所以我觉得没必要
  • 时间戳转化

    1 自定义时间戳转化 2 使用Moment js JavaScript 日期处理类库 地址如下 Moment js 中午网
  • 主从复制报错Fatal error:The slave I/O thread stops because master and slave have equal MySQL server UUIDs;

    异常 在MySQL中开启主从复制失败 原因 先确定主机和从机的server id是否不一样 如果一样也会导致主从复制失败 主机和从机的server id在 etc my cnf配置文件中配置的 下面的结果不一致说明不是server id的问
  • Ubuntu系统下安装rpm安装包

    目录 前言 方法 前言 Ubuntu的软件包格式为deb 而RPM格式的包归属于红帽子Red Hat 在这直接使用命令是安装不了的 需要通过一个桥梁进行转换 方法 将其rpm的格式包转换为deb的格式包 具体转换通过alien进行转换 这个
  • 华为OD机试 Python 【分割数组的最大差值】

    题目 给你一个整数数组 尝试将其分成两部分 左边和右边 然后分别求它们的和 你能找到一种切分方式 使得两边和的差的绝对值最大吗 输入 第一行是一个整数n 表示数组中的元素数量 其中 1 lt n 100000 第二行包含n个整数 它们组成了
  • 一个集成的BurpSuite漏洞探测插件1.2

    4 DNSLog查询漏报 注 扫描结束后才会在BurpSuite的Target Dashboard模块显示高危漏洞 进程扫描中无法进行同步 但可以在插件中查看 涉及到DoPassive方法问题
  • Ninth season twelfth episode,Phoebe fed a bunch of rats!!!!!!

    Scene Coffee place Joey is there Chandler is entering Chandler Hey Joey Hey So where s Mon Chandler Oh she s at home put
  • Keil报错:cannot open source input file “core_cmInstr.h“ 解决办法

    文章目录 前言 参考资料 历史精选文章 前言 前几天在面包板社区申请了一块uFun开发板 昨天刚到手 在烧录Demo程序的时候遇到一个问题 就是Keil打开工程 编译 报很多错误cannot open source input file c
  • Angular 4.x Forms patchValue and setValue

    在 Angular 4 x 中有多种方式可以更新表单的值 对于使用响应式表单的场景 我们可以通过框架内部提供的 API 如 patchValue 和 setValue 方便地更新表单的值 这篇文章我们将介绍如何使用 patchValue 和
  • J-link烧录MCU镜像文件

    1 使用范围 本文档基于NXP M4芯片 介绍MCU镜像文件烧录流程以及在烧录过程中遇到的问题 2 烧录步骤2 1 资源准备 烧录前需准备MCU镜像文件 镜像文件一般由Keil工具 SylixOS IDE工具或者其他工具生成 本文档以Kei
  • 读写分离与分库分表,涉及sharding-JDBC、sharding-sphere、停机迁移和双写方案、分布式id

    一 读写分离 1 1 何为读写分离 读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上 这样的话 就能够小幅提升写性能 大幅提升读性能 一主多从 也就是一台主数据库负责写 其他的从数据库负责读 主库和从库之间会进行数据同步 以保
  • ERP管理系统的权限控制实现--shiro

    1 Shiro基本原理分析 Authentication 身份认证 登录 验证用户是不是拥有相应的身份 Authorization 授权 即权限验证 验证某个已认证的用户是否拥有某个权限 即判断用户是否能做事情 常见的如 验证某个用户是否拥