Shiro入门学习二

来源:互联网 发布:51单片机有趣的小制作 编辑:程序博客网 时间:2024/05/19 14:02

Shiro入门学习二

Apache Shiro是Java的一个安全(权限)框架

Shiro相比于Spring security更加便捷,不仅使用Java Se环境,也可以用在Java EE环境

Shiro的作用:

  • 认证 - 例如登录
  • 授权 - 权限管理
  • 加密 - 例如密码可以用Shiro进行加密
  • 会话管理 -
  • web继承
  • 缓存

Shiro功能简介

这里写图片描述

  • Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
  • Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
  • Web Support:Web支持,可以非常容易的集成到Web环境;
  • Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
  • Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  • Testing:提供测试支持;
  • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

记住一点,Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。

Shiro的架构(对使用者)

这里写图片描述

  • Subject - 代表当前的用户
  • Shiro SecurityManager - 安全管理器
  • Realm - Shiro从Realm获取安全数据(如用户、角色、权限)

Shiro环境的搭建

JavaSE环境搭建Shiro框架

1.所需要的jar包

  • apache-log4j-1.2.15.jar
  • shiro-all-1.3.2.jar
  • slf4j-log4j12-1.6.1.jar
  • slf4j.api-1.6.1.jar

2.配置文件

可以从Shiro源码文件中的sample中拷贝过来

  • shiro.ini文件:存储数据,如用户名、密码、角色、权限
  • log4j.properties

shiro.ini文件内容及说明:

1.shiro中user存储数据格式

用户名=密码, 角色1, 角色2......

一个用户名可以有多个角色,如:

[users]# user 'root' with password 'secret' and the 'admin' role# 用户 root 密码 secret 角色 adminroot = secret, admin# user 'guest' with the password 'guest' and the 'guest' role# 用户 guest 密码 guest 角色 guestguest = guest, guest# user 'presidentskroob' with password '12345' ("That's the same combination on# my luggage!!!" ;)), and role 'president'# 用户 presidentskroob 密码 12345 角色 presidentpresidentskroob = 12345, president# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'# 用户 darkhelmet 密码 ludicrousspeed 角色 darklord schwartzdarkhelmet = ludicrousspeed, darklord, schwartz# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'# 用户 lonestarr 密码 vespa 角色 goodguy schwartzlonestarr = vespa, goodguy, schwartz

2.一个角色可能会对个多个权限

[roles]# 'admin' role has all permissions, indicated by the wildcard '*'# admin 具有所有权限admin = *# The 'schwartz' role can do anything (*) with any lightsaber:schwartz = lightsaber:*# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with# license plate 'eagle5' (instance specific id)goodguy = winnebago:drive:eagle5

3.测试获取session对象

如下的HelloWorld类:

package com.shiro.bean;import org.apache.shiro.SecurityUtils;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.session.Session;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class HelloWorld {    private static final Logger log = LoggerFactory.getLogger(HelloWorld.class);    public static void main(String[] args) {        log.info("正在测试log4j......");        //1.获取安全管理器        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");        SecurityManager securityManager = factory.getInstance();        //2.设置安全管理器        SecurityUtils.setSecurityManager(securityManager);        //3.获取Subject对象,为即将登录的用户        Subject currentUser = SecurityUtils.getSubject();        //4.获取session        Session session = currentUser.getSession();        session.setAttribute("name", "wz");        String value = (String) session.getAttribute("name");        if (value != null ) {            log.info("Shiro获取session会话对象当中指定的值:" + value);        }    }}

运行后,在控制台正确的输出了结果

Shiro认证过程

Shiro认证过程可参阅官网Authentication Sequence,如下图所示:

Shiro认证过程

1.判断currentUser是否登录过,currentUser.isAuthenticated() == false表示没有登录过

2.如果没有登录过,需要给当前的subject设置用户名和密码,使用UsernamePasswordToken

3.登录,可能会抛出如下的异常

  • UnknownAccountException - 错误的帐号
  • IncorrectCredentialsException - 错误的凭证
  • LockedAccountException - 锁定的帐号
  • DisabledAccountException - 禁用的帐号
  • ExcessiveAttemptsException - 登录失败次数过多
  • ExpiredCredentialsException - 过期的凭证

代码如下:

        if (currentUser.isAuthenticated() == false) {            UsernamePasswordToken token = new UsernamePasswordToken("root", "secret");            token.setRememberMe(true);//记住我            try {                currentUser.login(token);                log.info("用户名和密码正确");            } catch (UnknownAccountException e) {                log.info("账户不存在");            }catch (IncorrectCredentialsException e) {                log.info("密码错误");            }catch (LockedAccountException e) {                log.info("用户已经锁死");            }catch (AuthenticationException e) {                log.info("认证异常");            }        }

Shiro角色、权限认证过程

1.判断某个用户拥有指定的角色

        if (currentUser.hasRole("admin")) {            log.info("拥有指定的角色");        }else{            log.info("不拥有指定的角色");        }

2.判断某个用户拥有指定的权限

        if (currentUser.isPermitted("winnebago:drive:eagle5")) {            log.info("拥有指定的权限");        }else{            log.info("不拥有指定的权限");        }

Shiro Web-App 搭建

参考官网Securing Web Applications with Apache Shiro,使用maven来搭建一个Web-App的shiro项目,可以在Github上fork一个tutorial project,看参考pom.xml中内容

主要步骤是:
1.在src/main/webapp/WEB-INF/shiro.ini目录下创建shiro.ini文件
2.在web.xml中启用shiro

<listener>    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class></listener><filter>    <filter-name>ShiroFilter</filter-name>    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class></filter><filter-mapping>    <filter-name>ShiroFilter</filter-name>    <url-pattern>/*</url-pattern>    <dispatcher>REQUEST</dispatcher>    <dispatcher>FORWARD</dispatcher>    <dispatcher>INCLUDE</dispatcher>    <dispatcher>ERROR</dispatcher></filter-mapping>

默认过滤器

默认过滤器的介绍参考Default Filters

Filter Name Class anon org.apache.shiro.web.filter.authc.AnonymousFilter authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter logout org.apache.shiro.web.filter.authc.LogoutFilter noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter port org.apache.shiro.web.filter.authz.PortFilter rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter ssl org.apache.shiro.web.filter.authz.SslFilter user org.apache.shiro.web.filter.authc.UserFilter

Shiro Spring、SpringMVC框架搭建

1.在web.xml中配置shiroFilter

    <!-- Shiro Filter is defined in the spring application context: -->    <!-- Filter的代理类 -->    <filter>        <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>

Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制

ShiroFilter类似于Strut2/SpringMVC这种web框架的前端控制器,是安全控制的入口点,其负责读取配置(如ini配置文件),然后判断URL是否需要登录/权限等工作

ShiroFilter如何控制哪些web资源是需要登录才能访问,哪些不需要?

ShiroFilter提供了2中方式:

ShiroFilter的工作原理

  • filterChainDefinitions 过滤链的定义
  • 如果是没有经过认证,则会自动走到loginUrl

DelegatingFilterProxy的作用是自动到Spring容器查找名为shiroFilter(filter-name)的bean,并把Filter的操作委托给它。

DelegatingFilterProxy其源码定义如下:

public class DelegatingFilterProxy extends GenericFilterBean {    private String contextAttribute;    private WebApplicationContext webApplicationContext;    private String targetBeanName;    private boolean targetFilterLifecycle = false;    private volatile Filter delegate;    ......

其中:

  • targetBeanName - 存储即将获取的shiro核心过滤器的id值,如果没有指定这个targetBeanName,则自动获取filter的名字
  • delegate - 代表获取Spring的shiro的核心过滤器

2.Spring配置文件中shiro的配置

Spring配置文件applicationContext.xml中shiro的配置,可在shiro的源码文件中的sample例子找到,如下:

这里写图片描述

这里推荐大家参考在 Web 项目中应用 Apache Shiro

applicationContext.xml中shiro的配置内容如下:

    <!-- 安全管理器 -->      <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <!-- 缓存管理器 -->        <property name="cacheManager" ref="cacheManager" />        <!-- 处理数据 -->        <property name="realm" ref="jdbcRealm" />    </bean>    <!-- 可以使用的缓存技术,这里默认使用EHCACH -->     <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">            <!-- 缓存的位置 -->            <property name="cacheManagerConfigFile"  value="classpath:ehcache.xml"/>    </bean>    <!-- Realm -->    <bean id="jdbcRealm" class="com.shiro.bean.ShiroRealm">    </bean>    <!-- 必须要有这样的实例,用来管理spring容器当中的shiro常见的对象 -->    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />    <!-- 启用shiro注解 -->    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">        <property name="securityManager" ref="securityManager" />    </bean>    <!-- 网络方面 -->    <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">        <property name="securityManager" ref="securityManager" />    </bean>    <!-- 配置过滤器 -->    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager" />        <!-- 登录页面 -->        <property name="loginUrl" value="/logon.jsp" />        <!-- 认证登录成功后跳转的页面 -->        <property name="successUrl" value="/s/index" />        <!-- 未授权的页面 -->        <property name="unauthorizedUrl" value="/abc.jsp" />        <!-- 过滤链的定义 -->        <property name="filterChainDefinitions">            <value>                /logon.jsp = anon                /** = authc            </value>        </property>    </bean>

一些说明:

1.securityManagerrealm 属性,配置为我们自己实现的 Realm
2.shiroFilter这个beanid必须要与web.xml文件中的filter-name一致

  • loginUrl - 登录页面地址
  • successUrl - 为登录成功页面地址(如果首先访问受保护 URL 登录成功,则跳转到实际访问页面)
  • unauthorizedUrl - 认证未通过访问的页面

3.shiroFilterfilterChainDefinitions 属性

  • anon - 表示匿名访问(不需要认证与授权)
  • authc - 表示需要认证

这样配置后,假设我现在访问http://localhost:8080/ShiroDemo02/success.jsp页面,则会自动跳转到http://localhost:8080/ShiroDemo02/logon.jsp,其响应头为:

这里写图片描述

其中302表示重定向

认证资源格式及URL匹配模型

[urls]部分的配置,其格式是 url=拦截器[参数],拦截器[参数]

如果当前请求的url匹配[urls]部分的某个url模式,将会执行其配置的拦截器

URL匹配模式

url模式使用Ant风格模式
Ant路劲通配符支持?***,注意通配符匹配不包括目录分隔符”/”

  • ? - 匹配一个字符,如/admin?将匹配/admin1,但不匹配/admin/admin/
  • * - 匹配零个或多个字符串,如/admin将匹配/admin/admin123,但不匹配/admin/1
  • ** - 匹配路劲中的零个或多个路径,如/admin/**将匹配/admin/a/admin/a/b

URL匹配顺序

URL权限采取第一次匹配优先的方式,即从头开始使用第一个匹配的url模式对应的拦截器链

如:

  • /bb/**= filter1
  • /bb/aa = filter2
  • /** = filter3

如果请求的url是"/bb/aa",因为按照声明顺序进行匹配,那么将使用filter1进行拦截

JSP标签

JSP标签参考JSP / GSP Tag Library,也可参阅第九章 JSP标签——《跟我学Shiro》

导入标签库

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

1.principal标签

<shiro: principal/>

显示用户身份信息,默认调用Subject.getPrincipal()获取,即Primary Principal。

2.guest标签

用户没有身份验证时显示相应信息,即游客访问信息。

3.user标签

用户已经身份验证/记住我登录后显示相应的信息。

4.hasPermission标签

如果当前Subject有权限将显示body体内容。

<shiro:hasPermission name="user:add"><a href="<%=path %>/user/add.jsp">用户添加</a><br/></shiro:hasPermission>

5.hasRole标签

如果当前Subject有角色将显示body体内容。

<shiro:hasRole name="admin"><a href="<%=path %>/admin/">管理员页面</a><br/></shiro:hasRole>

教程

  • 在 Web 项目中应用 Apache Shiro
原创粉丝点击