Shiro安全框架

   

京淘权限管理子系统

 Shiro安全框架

 

 

1.  Shiro安全框架简介. 1-2

1.1.    Shiro 概述. 1-2

1.2.    Shiro 概要架构. 1-2

1.3.    Shiro 详细架构. 1-3

2.  Shiro 认证与授权分析. 2-4

2.1.    Shiro 认证流程. 2-4

2.2.    Shiro 授权流程. 2-5

3.  Shiro 框架基本配置. 3-6

3.1.    Shiro 基本依赖配置. 3-6

3.2.    Shiro 认证基本配置(xml方式) 3-6

3.3.    Shiro 授权基本配置(xml方式) 3-7

4.  Shiro 框架认证流程应用实现. 4-8

4.1.    服务端实现. 4-8

4.1.1. Dao接口实现. 4-8

4.1.2. Mapper元素定义. 4-9

4.1.3. Service 接口实现. 4-9

4.1.4. Controller类实现. 4-10

4.2.    客户端实现. 4-11

4.2.1. 编写用户登陆页面. 4-11

4.2.2. 异步登陆操作实现. 4-12

5.  Shiro 框架授权流程应用实现. 5-12

5.1.    服务端实现. 5-12

5.1.1. Dao 实现. 5-12

5.1.2. Mapper实现. 5-13

5.1.3. Service实现. 5-15

5.2.    授权检测实现. 5-16

6.  Shiro框架应用增强. 6-16

6.1.1. Shiro 缓存配置. 6-16

6.1.2. Shiro 记住我. 6-17

7.  总结. 7-17

7.1.    重点和难点分析. 7-17

7.2.    常见FAQ 7-17

 

1. Shiro安全框架简介

1.1.  Shiro 概述

Shiro是apache旗下一个开源安全框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。

课后了解:Spring security 安全框架

 

1.2.  Shiro 概要架构

 

在概念层,Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。

 

 

 

 

1.3.  Shiro 详细架构

Shiro 的核心架构思想如下图所示:

 

 

通过Shiro框架进行权限管理时,要涉及到的一些核心对象,主要包括:

认证管理对象,授权管理对象,会话管理对象,缓存管理对象,加密管理对象

以及Realm管理对象(领域对象:负责处理认证和授权领域的数据访问题)

 

1)  Subject(主体):与软件交互的一个特定的实体(用户、第三方服务等)。

2)  SecurityManager(安全管理器) :Shiro 的核心,用来协调管理组件工作。

3)  Authenticator(认证管理器):负责执行认证操作

4)  Authorizer(授权管理器):负责授权检测

5)  SessionManager(会话管理):负责创建并管理用户 Session 生命周期,提供一个强有力的 Session 体验。

6)  SessionDAO:代表 SessionManager 执行 Session 持久(CRUD)动作,它允许任何存储的数据挂接到 session 管理基础上。

7)  CacheManager(缓存管理器):提供创建缓存实例和管理缓存生命周期的功能

8)  Cryptography(加密管理器):提供了加密方式的设计及管理。

9)  Realms(领域对象):是shiro和你的应用程序安全数据之间的桥梁。

 

2. Shiro 认证与授权分析

2.1.  Shiro 认证流程

身份认证:判定用户是否是系统的合法用户。

用户访问系统资源时的认证(对用户身份信息的认证)流程如下:

 

 

 

具体流程分析如下:

 

1)系统调用subject的login方法将用户信息提交给SecurityManager

2)SecurityManager将认证操作委托给认证器对象Authenticator

3)Authenticator将身份信息传递给Realm。

4)Realm访问数据库获取用户信息然后对信息进行封装并返回。

5)Authenticator 对realm返回的信息进行身份认证。

 

思考:不使用shiro框架如何完成认证操作?filter,intercetor

 

2.2.  Shiro 授权流程

授权:对用户资源访问的授权(是否允许用户访问此资源)

用户访问系统资源时的授权流程如下:

 

 

 

 

1)系统调用subject相关方法将用户信息(例如isPermitted)递交给SecurityManager

2)SecurityManager将权限检测操作委托给Authorizer对象

3)Authorizer将用户信息委托给realm.

4)Realm访问数据库获取用户权限信息并封装。

5) Authorizer对用户授权信息进行判定。

 

 

思考:思考不使用shiro如何完成授权操作?intercetor,aop

 

3. Shiro 框架基本配置

3.1.  Shiro 基本依赖配置

 

添加shiro框架依赖(spring整合shiro)

  <dependency>

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

   <artifactId>shiro-spring</artifactId>

   <version>1.3.2</version>

  </dependency>

 

3.2.  Shiro 认证基本配置(xml方式)

创建spring-shiro.xml配置文件(tomcat启动时候要加载此配置文件文件),并添加如下配置:

 

配置SecurityManager对象

 

<bean id="securityManager"

             class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

             <property name="Realm" ref="shiroUserRealm"/>

 </bean>

 

配置ShiroFilterFactoryBean对象

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

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

         <!-- 设置此项的目的是让用户进行登录认证 -->

         <property name="LoginUrl" value="/doLoginUI.do"/>

         <!-- 设置请求过滤规则 -->

         <property name="FilterChainDefinitionMap">

            <map>

               <entry key="/bower_components/**" value="anon"/>

               <entry key="/build/**" value="anon"/>

               <entry key="/dist/**" value="anon"/>

               <entry key="/plugins/**" value="anon"/>

               <entry key="/**" value="authc"/><!-- 必须认证 -->

            </map>

         </property>

</bean>

 

在项目的web.xml文件中添加如下配置:

 

<filter>

     <filter-name>shiroFilter</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

     <init-param>

        <param-name>targetBeanName</param-name>

        <param-value>shiroFilterFactory</param-value>

     </init-param>

  </filter>

  <filter-mapping>

     <filter-name>shiroFilter</filter-name>

     <url-pattern>/*</url-pattern>

  </filter-mapping>

 

说明:

1)  targetBeanName 名字由DelegatingFilterProxy对象底层设置并读取。

2)  shiroFilterFactory 名字要与ShiroFilterFactoryBean配置的id相同。

 

 

3.3.  Shiro 授权基本配置(xml方式)

 

在spring-shiro.xml中追加如下配置:

 

     <!-- 配置bean对象的生命周期管理 -->

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

     </bean>

 

     <!-- 配置Bean对象的代理 -->

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

           depends-on="lifecycleBeanPostProcessor">

     </bean>

 

     <!-- 配置授权属性-->

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

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

     </bean>

 

ss

4. Shiro 框架认证流程应用实现

本讲的shiro应用主要讲解shiro是集成到spring如何实现权限控制

4.1.  服务端实现

 

4.1.1. Dao接口实现

业务描述

在SysUserDao中根据用户名获取用户对象

 

业务实现(根据用户名查询用户对象的方法定义)

1)  返回值SysUser

2)  方法名findUserByUserName

3)  参数列表(String username)

 

代码实现:

 

 

SysUser findUserByUserName(String username);

 

4.1.2. Mapper元素定义

根据SysUserDao中定义的方法,添加元素定义

 

  <select id="findUserByUserName"

           resultType="com.jt.sys.entity.SysUser">

      select *

      from sys_users 

      where username=#{username}

   </select>

 

4.1.3. Service 接口实现

业务描述

本模块的service可以借助realm实现,我们编写realm时可以继承AuthorizingRealm并重写相关方法完成相关业务的实现。

业务实现:(创建realm类并重写相关方法)

1)     包名:com.jt.sys.service.realm.ShiroUserRealm

2)     类名:ShiroUserRealm

3)     方法:AuthenticationInfo (完成认证信息的获取与封装)

 

@Service

public class ShiroUserRealm extends AuthorizingRealm {

 

 

    @Autowired

    private SysUserDao sysUserDao;

    /**

     * 设置凭证匹配器

     * @param credentialsMatcher

     */

    @Override

    public void setCredentialsMatcher(

CredentialsMatcher credentialsMatcher) {

        HashedCredentialsMatcher cMatcher=

        new HashedCredentialsMatcher();

        cMatcher.setHashAlgorithmName("MD5");

        super.setCredentialsMatcher(cMatcher);

    }

    /**

     * 执行认证操作时,此方法用户获取用户认证信息

     * 说明:此方法由认证管理器调用

     */

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(

AuthenticationToken token)throws AuthenticationException {

        //1.获取客户端提交的用户信息

        UsernamePasswordToken upToken=

        (UsernamePasswordToken)token;

        String username=upToken.getUsername();

        //2.基于用户名从数据库查询用户信息

        SysUser user=sysUserDao.findUserByUserName(username);

        //3.校验用户信息(用户存在吗)

        if(user==null)

        throw new AuthenticationException();

        //4.对用户信息进行封装

        ByteSource credentialsSalt=

        ByteSource.Util.bytes(user.getSalt());

        SimpleAuthenticationInfo info=

        new SimpleAuthenticationInfo(

        user, //principal(用户身份)

        user.getPassword(),//hashedCredentials(已经加密的密码)

        credentialsSalt, //credentialsSalt(盐)

        this.getName());//realm name

        return info;//此对象返回给谁了?认证管理器

    }

    /**执行授权操作时,此方法用于获取用户的权限信息*/

    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(

            PrincipalCollection principals) {

        //完成授权操作时需要在此方法完成数据获取与封装

         //。。。。。。。。

        return null;

    }

}

 

4.1.4. Controller类实现

业务描述

1)  在SysUserService接口及实现类中添加登录方法

2)  接收用户名及密码参数,并对其进行有效验证

3)  执行登录认证

 

代码实现

 

@RequestMapping("/")

@Controller

public class SysLoginController {

       @RequestMapping("doLoginUI")

       public String doLoginUI(){

           return "login";

       }

       @RequestMapping("doLogin")

       @ResponseBody

       public JsonResult doLogin(String username,String password){

           //1.获取Subject对象

           Subject subject=SecurityUtils.getSubject();

           //2.通过Subject提交用户信息,交给shiro框架进行认证操作

           //2.1对用户进行封装

           UsernamePasswordToken token=

           new UsernamePasswordToken(

                   username,//身份信息

                   password);//凭证信息

           //2.2对用户信息进行身份认证

           subject.login(token);

           //分析:

           //1)token会传给shiro的SecurityManager

           //2)SecurityManager将token传递给认证管理器

           //3)认证管理器会将token传递给realm

           return new JsonResult("login ok");

       }

}

 

 

4.2.  客户端实现

4.2.1. 编写用户登陆页面

在WEB-INF/pages/目录下添加登陆页面(login.html)

4.2.2. 异步登陆操作实现

 

  $(function () {

    $(".login-box-body").on("click",".btn",doLogin);

  });

  function doLogin(){

      var params={

         username:$("#usernameId").val(),

         password:$("#passwordId").val()

      }

      var url="doLogin.do";

      $.post(url,params,function(result){

          if(result.state==1){

            //跳转到indexUI对应的页面

            location.href="indexUI.do?t="+Math.random();

          }else{

            $(".login-box-msg").html(result.message);

          }

      });

  }

 

 

5. Shiro 框架授权流程应用实现

5.1.  服务端实现

5.1.1. Dao 实现

业务描述:(核心业务是基于用户id获取用户对应的权限)

1)  基于用户id查找角色id信息

2)  基于角色id查找菜单id信息

3)  基于菜单id查找权限标识信息

 

业务实现:(在SysUserDao中基于用户id查找角色id信息)

1)  返回值 List<Integer>

2)  方法名 findRoleIdsByUserId

3)  参数列表(Integer id)

 

 

业务实现:(在SysRoleMenuDao中基于用户id查找菜单id信息)

1)  返回值 List<Integer>

2)  方法名 findMenuIdsByRoleId

3)  参数列表(Integer[] id)

 

业务实现:(在SysMenuDao中基于菜单id查找权限标识信息)

1)  返回值 List<String>

2)  方法名 findPermisssions

3)  参数列表(Integer[] id)

 

代码实现:

SysUserRoleDao 中方法定义

    List<Integer> findRoleIdsByUserId(

            Integer id);

 

 

 

 

 

SysRoleMenuDao中方法定义

    List<Integer> findMenuIdsByRoleId(

            @Param("roleIds")Integer...roleIds);

 

SysMenuDao中方法定义

    List<String> findPermissions(

            @Param("menuIds")

            Integer... menuIds);

 

 

 

5.1.2. Mapper实现

业务描述

基于Dao中方法,定义映射元素

 

代码实现:

SysUserRoleMapper中元素定义

    <select id="findRoleIdsByUserId"

            resultType="int">

           select role_id

           from sys_user_roles

           where user_id=#{userId}       

</select>

 

SysRoleMenuMapper中元素定义

    <select id="findMenuIdsByRoleId"

         resultType="int">

         select menu_id

         from sys_role_menus

         where role_id in

         <foreach collection="roleIds"

                  open="("

                  close=")"

                  separator=","

                  item="item">

               #{item}

         </foreach>

     </select>

 

 

 

SysMenuMapper中元素定义

    <select id="findPermissions"

           resultType="string">

       select permission <!-- sys:user:update -->

       from sys_menus

       where id in

       <foreach collection="menuIds"

                open="("

                close=")"

                separator=","

                item="item">

            #{item}

       </foreach>

   </select>

 

5.1.3. Service实现

业务描述

重写对象realm的doGetAuthorizationInfo方法,并完成用户权限信息的获取以及封装,最后将信息传递给授权管理器完成授权操作。

 

 

@Service

public class ShiroUserRealm extends AuthorizingRealm {

    @Autowired

    private SysUserRoleDao sysUserRoleDao;

    @Autowired

    private SysRoleMenuDao sysRoleMenuDao;

    @Autowired

    private SysMenuDao sysMenuDao;

    

    ……

    /**执行授权操作时,此方法用于获取用户的权限信息*/

    @Override

    protected AuthorizationInfo

    doGetAuthorizationInfo(

            PrincipalCollection principals) {

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

        //1.获取用户对象(此对应依赖与认证时封装的用户身份)

        SysUser user=(SysUser)

        principals.getPrimaryPrincipal();

        //2.基于用户id查找角色Id

        List<Integer> roleIds=

        sysUserRoleDao.findRoleIdsByUserId(

                user.getId());

        //3.基于角色id查找菜单(资源)id

        Integer[] array={};

        List<Integer> menuIds=

        sysRoleMenuDao.findMenuIdsByRoleId(

                roleIds.toArray(array));

        //4.基于菜单id查找权限标识

        List<String> permisssions=

        sysMenuDao.findPermissions(

                menuIds.toArray(array));

        //5.封装权限信息(AuthorizationInfo)

        Set<String> pSet=

        new HashSet<String>();

        for(String permission:permisssions){

            if(!StringUtils.isEmpty(permission)){

                pSet.add(permission);

            }

        }//去重和空(null),空串

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

        SimpleAuthorizationInfo info=

        new SimpleAuthorizationInfo();

        info.setStringPermissions(pSet);

        return info;

    }

}

 

 

5.2.  授权检测实现

 

在需要进行授权检测的方法上添加执行此方法需要的权限标识

例如

@RequestPermissions(“sys:user:valid”)

 

6. Shiro框架应用增强

6.1.1. Shiro 缓存配置

Step01: 添加ehcache 依赖

 

  <dependency>

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

    <artifactId>shiro-ehcache</artifactId>

   <version>1.3.2</version>

  </dependency>

 

 

Step02: 添加ehcache 配置文件

 

在项目的src/main/resources目录下添加ehcache.xml

 

Step03:  Spring 中配置ehcache 配置文件

 

 

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

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

</bean>

 

将cacheManager添加到securityManager中

     <bean id="securityManager"

           class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

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

         <property name="realm" ref="userRealm"></property>

     </bean>

 

6.1.2. Shiro 记住我

课后可自学

 

7. 总结

7.1.  重点和难点分析

 

7.2.  常见FAQ

 

转载于:https://www.cnblogs.com/robinAndLaurel/p/9816394.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值