Shiro安全框架入门

完整学习网址:https://www.w3cschool.cn/shiro

一、Shiro简介

1、Shiro的概念

Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能。

认证(Authentication):用户身份识别,常被称为用户“登录”,判断用户是否登陆,如果未登陆,则拦截其请求。优点:可以实现单点登录,多个子系统登录一个其他子系统也自动登录。(如登录了淘宝,天猫也自动登录了)

授权(Authorization):访问控制。当用户登陆后,判断其身份是否有权限访问相应的资源,如果没有权限则拦截

密码加密(Cryptography):保护或隐藏数据防止被偷窃。将MD5进行二次封装,让其更加容易使用。注意MD5不可逆运算

会话管理(Session Management)

Shiro的三大核心组件

Subject:正与系统进行交互的人,或某一个第三方服务。所有Subject实例都被绑定到(且这是必须的)一个SecurityManager上。

SecurityManager:Shiro架构的心脏,典型的Facade模式。用来协调内部各安全组件,管理内部组件实例,并通过它来提供安全管理的各种服务。当Shiro与一个Subject进行交互时,实质上是幕后的SecurityManager处理所有繁重的Subject安全操作。

Realms:本质上是一个特定安全的DAO。当配置Shiro时,必须指定至少一个Realm用来进行身份验证和/或授权。Shiro提供了多种可用的Realms来获取安全相关的数据。如关系数据库(JDBC),INI及属性文件等。可以定义自己Realm实现来代表自定义的数据源。

Shiro 完整架构图

2、Shiro内置过滤器

Shiro的内置过滤器分为两组:

认证过滤器:anon(不认证也可以访问),authcBasic, authc(必须认证后才可访问)

授权过滤器:perms(指定资源需要哪些权限才可以访问),Roles, ssl, rest, port


过滤器名称


过滤器类


描述


anon


org.apache.shiro.web.filter.authc.AnonymousFilter


匿名过滤器


authc


org.apache.shiro.web.filter.authc.FormAuthenticationFilter


如果继续操作,需要做对应的表单验证否则不能通过


authcBasic


org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter


基本http验证过滤,如果不通过,跳转登录页


perms


org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter


权限过滤器


port


org.apache.shiro.web.filter.authz.PortFilter


端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面


rest


org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter


http方法过滤器,可以指定如post不能进行访问等


roles


org.apache.shiro.web.filter.authz.RolesAuthorizationFilter


角色过滤器,判断当前用户是否指定角色


ssl


org.apache.shiro.web.filter.authz.SslFilter


请求需要通过ssl,如果不是跳转登录页


user


org.apache.shiro.web.filter.authc.UserFilter


如果访问一个已知用户,比如记住我功能,走这个过滤器

二、基本使用

配合Demo说明基本使用方法

项目环境:Eclipse+SSH

1、ERP整合Shiro

1)添加依赖

在erp_parent父工程的pom.xml添加依赖

<properties>
    <shiro.ver>1.2.3</shiro.ver>
</properties>

<dependencies>
    <!-- shiro -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>${shiro.ver}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>${shiro.ver}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>${shiro.ver}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-aspectj</artifactId>
        <version>${shiro.ver}</version>
    </dependency>
</dependencies>

2)配置web.xml, 添加过滤器代理DelegatingFilterProxy,要放在struts2的核心过滤器之前

    <!-- 配置shiro的过滤器代理DelegatingFilterProxy -->
    <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>*.action</url-pattern>
        <url-pattern>*.html</url-pattern>
        <url-pattern>*</url-pattern>
    </filter-mapping>

Spring提供的一个简便的过滤器处理方案,它将具体的操作交给内部的Filter对象delegate去处理,而这个delegate对象通过Spring的IOC容器获取,这里采用的是Spring的FactorBean的方式获取这个对象。虽然配置了这一个filter,但是它并没做任何实际的工作,而是把这个工作交由Spring容器中一个bean的id为shiroFilter的类,即ShiroFilterFactoryBean。

3)添加shiro核心控制器的spring配置文件applicationContext_shiro.xml在erp_web的资源目录下(中间省略了部分业务相关的配置)

注意过滤链的顺序,匿名-->授权-->认证

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        "> 

    <!-- shiro的过滤工厂,相当默认的加载了9个过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 安全管理器,shiro核心组件(大脑) Facade模式 -->
        <property name="securityManager" ref="securityManager" />
        <property name="filters">
            <map>
                <entry key="perms" value-ref="erpAuthorizationFilter"></entry>
            </map>
        </property>
        <!-- 认证相关配置:用户如果没有登陆,当他在访问资源的时候,就会自动跳转到登陆的页面 -->
        <property name="loginUrl" value="/login.html"></property>
        <!-- 授权相关配置:当用户没有访问某项资源权限的时候,跳转到该页面 -->
        <property name="unauthorizedUrl" value="/error.html"></property>
        <!-- 过滤链的定义:定义URL访问的时候对应的认证或授权时处理的过滤器 -->
        <property name="filterChainDefinitions">
            <value>
                /error.html = anon
                /login_*.action = anon
                /login_* = anon

                /emp_*=perms["用户角色设置","重置密码"]
                /goodstype.html=perms["商品类型"]
                /goodstype_*=perms["商品类型"]
                /goods.html=perms["商品"]
                /goods_*=perms["商品"]
                /orders.html=perms["采购订单查询","采购订单申请","采购订单审核","采购订单确认","采购订单入库","我的采购订单","销售订单查询","销售订单录入","销售订单出库"]
                /orders_*=perms["采购订单查询","采购订单申请","采购订单审核","采购订单确认","采购订单入库","我的采购订单","销售订单查询","销售订单录入","销售订单出库"]
                /report_*.html=perms["销售统计报表","销售趋势报表"]
                /report_*=perms["销售统计报表","销售趋势报表"]

                /*.html = authc
                /*.action = authc
                /* = authc
            </value>
        </property>
    </bean>

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

    <!-- 自定义的realm -->
    <bean id="erpRealm" class="cn.itcast.erp.realm.ErpRealm">
        <property name="empBiz" ref="empBiz"></property>
    </bean>

    <!-- 自定义的过滤器 -->
    <bean id="erpAuthorizationFilter" class="cn.itcast.erp.filter.ErpAuthorizationFilter"></bean>
</beans>

4)创建error.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>提示信息</title>
</head>
<body>
尊敬的用户,您没有访问权限!
</body>
</html>

2、认证功能

1)LoginAction的checkUser方法中使用Subject自带的login方法

说明:UsernamePasswordToken是AuthenticationToken的子接口的实现类,它是对用户名和密码的封装。

Subject是对当前用户执行操作的封装,此处用它来执行登陆的操作。如果用户名和密码错误,login方法会抛出AuthenticationException异常

public void checkUser() {
    try {
        //1. 创建令牌,身份证明
        UsernamePasswordToken upt = new UsernamePasswordToken(username,pwd);
        //2. 获取主题 subject: 封装当前用户的一些操作
        Subject subject = SecurityUtils.getSubject();
        //3. 执行login
        subject.login(upt);
    } catch (Exception e) {
        e.printStackTrace();
    }
 }

2)自定义Realm

Realm的概念:Realm是Shiro与应用安全数据间的“桥梁”或者“连接器”。实质上是一个安全相关的DAO,它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。可以配置多个Realm。

作业流程:使用subject.login方法后,并不会调用登陆的业务层进行登陆的验证查询,即不会从数据库查找登陆的用户名和密码是否正确,而是将这项工作交给shiro去完成。

shiro通过Realm找到我们提供的登陆验证业务,验证登陆的用户名和密码是否正确。因此真正实现登陆验证的是Realm,而shiro只是去调Realm。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

a)在erp_web子工程下创建包cn.itcast.erp.realm

b)创建ErpRealm类继承自AuthorizingRealm

public class ErpRealm extends AuthorizingRealm {

    private IEmpBiz empBiz;

    public void setEmpBiz(IEmpBiz empBiz) {
        this.empBiz = empBiz;
    }

    /**
     * 认证
     * @return null:认证失败, AuthenticationInfo实现类,认证成功
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //通过令牌得到用户名和密码
        UsernamePasswordToken upt = (UsernamePasswordToken) token;
        //得到密码
        String pwd = new String(upt.getPassword());
        //调用登录查询
        Emp emp = empBiz.findByUsernameAndPwd(upt.getUsername(), pwd);
        if(null != emp) {
            //构造参数1: 主角=登陆用户
            //参数2:授权码:密码
            //参数3:realm的名称
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(emp,pwd,getName());
            return info;
        }
        return null;
    }

}
empBiz.findByUsernameAndPwd方法
/**
* 用户登陆
* @param username
* @param pwd
* @return
*/
public Emp findByUsernameAndPwd(String username, String pwd) {
  //查询前先加密
  pwd = encrypt(pwd, username);
  return empDao.findByUsernameAndPwd(username, pwd);
}

empDao.findByUsernameAndPwd方法

public Emp findByUsernameAndPwd(String username, String pwd){
  String hql = "from Emp where username=? and pwd=?";
  List<Emp> list = (List<Emp>) this.getHibernateTemplate().find(hql, username, pwd);
  //能够匹配上,则返回第一个元素
  if(list.size() > 0){
    return list.get(0);
  }
  //如果登陆名或密码不正确
  return null;
}

c)applicationContext_shiro.xml中与自定义ErpRealm相关的配置

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

<!-- 自定义的realm -->
<bean id="erpRealm" class="cn.itcast.erp.realm.ErpRealm">
  <property name="empBiz" ref="empBiz"></property>
</bean>

注意:登录的action要配置为anon,不然由于配置了/*=authc,会强行跳转到登陆页面。

/login_*.action = anon
/login_* = anon

d)LoginAction中的loginOut方法也可以通过subject的getPrincipal方法提取主题对象。

Shiro提供了会话管理机制,实际上自定义的realm认证方法返回值对象中的主角对象就是登陆的用户,可以通过subject的getPrincipal方法将其提取出来。

/**
* 退出登陆
*/
public void loginOut() {
    //ActionContext.getContext().getSession().remove("loginUser");
    SecurityUtils.getSubject().logout();
}

3、授权功能

授权就是通过设置规则,指定哪些URL需要哪些权限才可以访问。

在ErpRealm中新增授权方法作用:告诉shiro当前用户有什么权限

在applicationContext_shiro.xml增加配置信息作用:告诉shiro什么资源有什么权限才可以访问

1)授权方法与配置

a) 在ErpRealm中新增授权方法

/**
* 授权
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //获取当前用户
    Emp emp = (Emp) principals.getPrimaryPrincipal();
    //获取当前登陆用户的菜单权限
    List<Menu> menuList = empBiz.getMenusByEmpuuid(emp.getUuid());
    //加入授权
    for(Menu m : menuList) {
    //这里使用menuname来做授权里的key值,那么在配置授权访问的url=perms[菜单名称]
    info.addStringPermission(m.getMenuname());
    }
    return info;
}
empBiz.getMenusByEmpuuid方法
/**
* 根据员工编号获取菜单
* @param uuid
*/
public List<Menu> getMenusByEmpuuid(Long uuid) {
  return empDao.getMenusByEmpuuid(uuid);
}
empDao.getMenusByEmpuuid方法
public List<Menu> getMenusByEmpuuid(Long uuid) {
  String hql = "select m from Emp e join e.roles r join r.menus m where e.uuid=?";
  return (List<Menu>) this.getHibernateTemplate().find(hql, uuid);
}

b) applicationContext_shiro.xml中与配置授权控制规则相关的内容

/goodstype.html=perms["商品类型"]
/goodstype_*=perms["商品类型"]
/goods.html=perms["商品"]
/goods_*=perms["商品"]
/store.html=perms["仓库"]
/store_*=perms["仓库"]
/orders.html=perms["采购订单查询","采购订单申请","采购订单审核","采购订单确认","采购订单入库","我的采购订单","销售订单查询","销售订单录入","销售订单出库"]
/orders_*=perms["采购订单查询","采购订单申请","采购订单审核","采购订单确认","采购订单入库","我的采购订单","销售订单查询","销售订单录入","销售订单出库"]
/report_*.html=perms["销售统计报表","销售趋势报表"]
/report_*=perms["销售统计报表","销售趋势报表"]

2)自定义授权过滤器

当一个URL有多个权限需要访问的时候,如果按下面的方法来配置,系统默认使用的是and关系,即同时具备这两个权限才可以访问此URL

/orders.html=perms[“采购订单查询”,“采购订单审核”]

如果想要转换成or关系,即只要有具备一种就可以访问此URL,就需要自定义授权过滤器。

a)在erp_web子工程下创建包cn.itcast.erp.filter

b)创建自定义过滤器,继承自AuthorizationFilter

/**
 * 自定义授权过滤器
 */
public class ErpAuthorizationFilter extends AuthorizationFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        //获取主题
        Subject subject = getSubject(request,response);
        //orders.html=perms["采购订单的查询","采购订单的审核","采购订单的确认","采购订单的入库"]
        //mappedValue="采购订单的查询","采购订单的审核","采购订单的确认","采购订单的入库"
        String[] perms = (String[]) mappedValue;

        boolean isPermitted = true;
        if(null == perms || perms.length == 0){
            return isPermitted;
        }
        if(null != perms || perms.length > 0){
            for(String perm : perms) {
                //只要有一个权限,就返回true
                if(subject.isPermitted(perm)) {
                    return true;
                }
            }
        }
        return false;
    }

}

c)applicationContext_shiro.xml中配置过滤器相关内容

<property name="filters">
  <map>
    <entry key="perms" value-ref="erpAuthorizationFilter"></entry>
  </map>
</property>

<!-- 自定义的过滤器 -->
<bean id="erpAuthorizationFilter" class="cn.itcast.erp.filter.ErpAuthorizationFilter"></bean>

原文地址:https://www.cnblogs.com/anyueemo/p/9290964.html

时间: 2024-08-29 19:46:31

Shiro安全框架入门的相关文章

Shiro安全框架入门使用方法

详见:https://blog.csdn.net/qq_32651225/article/details/77199464 框架介绍Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任 何应用程序,从最小的移动应用程序到最大的网络和企业应用程序. Shrio的主要功能: Authentication:用户认证(登录)Authorization:权限控制Session Management:会话

Shiro安全框架入门篇(登录验证实例详解与源码)

一.Shiro框架简单介绍 Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权.Shiro在JavaSE和JavaEE项目中都可以使用.它主要用来处理身份认证,授权,企业会话管理和加密等.Shiro的具体功能点如下: (1)身份认证/登录,验证用户是不是拥有相应的身份: (2)授权,即权限验证,验证某个已认证的用户是否拥有某个权限:即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色.或者细粒度的验证某个用户对某个资源是否具有某个权限: (3)会话管理,即用户登录

Shiro安全框架入门篇

一.Shiro框架介绍 Apache Shiro是Java的一个安全框架,旨在简化身份验证和授权.Shiro在JavaSE和JavaEE项目中都可以使用.它主要用来处理身份认证,授权,企业会话管理和加密等.Shiro的具体功能点如下: (1)身份认证/登录,验证用户是不是拥有相应的身份: (2)授权,即权限验证,验证某个已认证的用户是否拥有某个权限:即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色.或者细粒度的验证某个用户对某个资源是否具有某个权限: (3)会话管理,即用户登录后就

Shiro安全框架【快速入门】就这一篇!

Shiro 简介 照例又去官网扒了扒介绍: Apache Shiro? is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro's easy-to-understand API, you can quickly and easily secure any ap

Shiro权限控制框架入门1:Shiro的认证流程以及基本概念介绍

前言:我在最开始学习Shiro这个框架时,在网上搜索到的一个介绍比较全面的教程是:<跟我学Shiro>系列教程.但是在我看了他写的前几篇文章后,我发现虽然他在这个系列教程中把shiro的一些特性介绍地非常全面详细,但是整个教程的叙述方式还是有很大缺陷的.文章与文章之间并没有很好地串联起来,每篇文章介绍的东西都过于分散了,如果是对shiro完全不了解的新手来看的话完全是一场噩梦.就像一个网友评价的这样: 看了看这个教程,看完之后都想放弃shiro了,完全看不懂,后来百度了很多别的资料才理解了sh

BOS项目 第7天(shiro权限框架进行认证和授权)

BOS项目笔记 第7天 今天内容安排: 1.权限概述(认证.授权) 2.常见的权限控制的方式(URL拦截权限控制.方法注解权限控制) 3.权限数据模型(权限表.角色表.用户表.角色权限关系表.用户角色关系表) 4.shiro框架入门 5.将shiro应用到bos项目中进行认证和授权 1. 权限概述 系统提供了很多功能,并不是所有的用户登录系统都可以操作这些功能.我们需要对用户的访问进行控制. 认证:系统提供的用于识别用户身份的功能(通常是登录功能)-----让系统知道你是谁?? 授权:系统提供的

shiro安全框架

原文:http://blog.csdn.net/boonya/article/details/8233303 可能大家早先会见过 J-security,这个是 Shiro 的前身.在 2009 年 3 月初之前,这个安全框架叫做 J-security,由于某些原因,更名为 Shiro(或者 Ki,意为 Fortress),是 Apache 的孵化项目,鉴于本文编写时 Shiro 的还没有正式发布的版本,本文使用的是 Jsecurity 的稳定版本 0.9,本文中 Shiro 等同于 Jsecur

Dwz(J-UI)框架--入门

http://www.cnblogs.com/chenyongsai/p/4933982.html Dwz(J-UI)框架--入门 一.了解 概述:是中国人自己开发的基于jQuery实现的Ajax RIA开源框架. 目的:简单实用.扩展方便(在原有架构基础上扩展方便).快速开发.RIA思路.轻量级 使用:用html扩展的方式来代替javascript代码 思路:根据官网页面样例,查看官方代码包,查阅相关子页面,参阅帮助文档,添加固定的标签属性语法 优势:第一次打开页面时载入界面到客户端, 之后和

Farseer.net轻量级开源框架 入门篇:使用前说明

导航 目   录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 框架性能测试 下一篇:Farseer.net轻量级开源框架 入门篇: 增.删.改.查操作演示 本篇讲解使用或者学习Farseer前需要知道一些事项: 在后续很多演示中,使用了很多扩展方法.但作者并没有明确出哪些是扩展的方法.所以读者要注意.在使用框架的时候,都需要引用扩展方法的命名空间:using FS.Extend; 为了方便,扩展方法统一放到FS.Extend中,在这里特别说