浅析shiro框架的认证和授权

shiro安全框架

1.1.Shiro 概述

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

1.2.Shiro 概要架构

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

1.3shiro的构件

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.1Shiro 认证

简述:
1)系统调用subject的login方法将用户信息提交给SecurityManager
2)SecurityManager将认证操作委托给认证器对象Authenticator
3)Authenticator将身份信息传递给Realm。
4)Realm访问数据库获取用户信息然后对信息进行封装并返回。
5)Authenticator 对realm返回的信息进行身份认证。

详述:
用户名密码验证为例,当浏览器客户端向服务器发送AJAX异步请求,请求服务器处理验证用户输入的用户名和密码,
当请求传入Tomcat,通过Tomcat的过滤器****到达前端控制器的时候,前端控制器截取请求的url,在HandlerMapping里找对应的map集合中的entry元素,找到后穿过springMVC的拦截器到达后端控制器Controller,在Controller里使用SecorityUtils获取一个Subject,subject里面有一个login方法,但是调用login方法必须传入一个token类型的参数,这时候我们想到AJAX里面传过来的username和password正好可以封装在一个UsernamePasswordtoken里面,所以我们这样写

UsernamePasswordToken tokensubjec = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.Subject();
subject.login(token);

当我们写完这句subject.login(token);
系统底层会帮我们从配置文件读取我们配置的SecurityManager以及相关配置,并将token传过去,会找到anthenticator(认证管理器),anthenticator根据SecurityManager里面配置的realm,找到realm。我们要做的就是在这之前一定要确保该realm已经存在,否则会找不到,在realm中我们将传过来token进行向下造型回usernamepasswordtoken,
然后将里面的username取出来传递到数据层,让数据层根据username从用户名中查询具体用户所有信息,查询完毕我们使用一个SimpleAuthenticationInfo进行信息封装,new一个该对象的时候我们要传入四个参数第一个是身份信息,我们一般传入从dao数据层查到的用户信息,但是要注意这里写入的类型和授权的时候取数据的类型要对应,如果只写用户名则取数据的时候用字符串接收,第二个参数是加密后的密码,我们已经查到,第三个参数是指定类型的salt,其实和我们通过数据层查到的salt是一样的只不过需要的类型不一致,需要做一步转型即可,第四个参数是realm的名字,表示本类直接用this.getName();然后将我们new出来的SimpleAuthenticationInfo对象的实例返回给认证管理器,认证管理器会自动帮我们认证。
如下图所示在这里插入图片描述

2.2Shiro的授权

概述:
1)系统调用subject相关方法将用户信息(例如isPermitted)递交给SecurityManager
2)SecurityManager将权限检测操作委托给Authorizer对象
3)Authorizer将用户信息委托给realm.
4)Realm访问数据库获取用户权限信息并封装。
5) Authorizer对用户授权信息进行判定。

3.基于注解的方式配置Shiro组件

@Bean("securityManager")
public DefaultWebSecurityManager  newDefaultWebSecurityManager(
			AuthorizingRealm userRealm){
		DefaultWebSecurityManager sManager=
		new DefaultWebSecurityManager();
		//此时必须保证realm对象已经存在了
		sManager.setRealm(userRealm);
		return sManager;
}


@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean newShiroFilterFactoryBean(
			SecurityManager securityManager){//shiro 包
		ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
		bean.setSecurityManager(securityManager);
	    //当此用户是一个非认证用户,需要先登陆进行认证
		bean.setLoginUrl("/doLoginUI.do");
		LinkedHashMap<String,String> fcMap=
		new LinkedHashMap<>();
		fcMap.put("/bower_components/**","anon");//anon表示允许匿名访问
		fcMap.put("/build/**", "anon");
		fcMap.put("/dist/**","anon");
		fcMap.put("/plugins/**","anon");
		fcMap.put("/doLogin.do","anon");
		fcMap.put("/doLogout.do","logout");
		fcMap.put("/**", "authc");//必须授权才能访问
		bean.setFilterChainDefinitionMap(fcMap);
		return bean;
}


@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor newLifecycleBeanPostProcessor(){
		return new LifecycleBeanPostProcessor();
}


@DependsOn(value="lifecycleBeanPostProcessor")
@Bean
public DefaultAdvisorAutoProxyCreator newDefaultAdvisorAutoProxyCreator(){
		return new DefaultAdvisorAutoProxyCreator();
}


@Bean
public AuthorizationAttributeSourceAdvisor newAuthorizationAttributeSourceAdvisor(
			SecurityManager securityManager){
		    AuthorizationAttributeSourceAdvisor bean=
			new AuthorizationAttributeSourceAdvisor();
		    bean.setSecurityManager(securityManager);
		return bean;
	}


3.3.Shiro 核心过滤器配置
在注解启动类中,重写onStartup方法,完成过滤器的注册
	@Override
	public void onStartup(ServletContext servletContext) 
throws ServletException {
		System.out.println("onStartup");
		//super.onStartup(servletContext);
		registerContextLoaderListener(servletContext);
		registerFilter(servletContext);
		registerDispatcherServlet(servletContext);
	}

	private void registerFilter(ServletContext servletContext) {
		//注册Filter对象
		//项目没有web.xml并且此filter不是自己写的,所以需要用这种配置方式
		FilterRegistration.Dynamic dy=
		servletContext.addFilter("filterProxy",
				DelegatingFilterProxy.class);
		dy.setInitParameter("targetBeanName","shiroFilterFactoryBean");
		dy.addMappingForUrlPatterns(
				null,//EnumSet<DispatcherType>
				false,"/*");//url-pattern
	}

4.基于xml方式配置Shiro组件

<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
	xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="  
       http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
       http://www.springframework.org/schema/mvc   
       http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd   
       http://www.springframework.org/schema/tx   
       http://www.springframework.org/schema/tx/spring-tx-4.3.xsd   
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util-4.3.xsd
       http://www.springframework.org/schema/data/jpa 
       http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<!-- 配置securityManager -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- 配置Realm -->
		<property name="Realms" ref="shiroUserRealm"></property>
		
	</bean>
	<!-- 生命周期管理器 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor">
	</bean>
	<!--设置自动代理Service实现类-->
	<bean id="defaultAdvisorAutoProxyCreator"
		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"></property>
	</bean>

	<!-- 配置shiro的shiroFilterFactoryBean -->
	<!-- 目的:让用户先进行登录认证 -->
	<bean id="shiroFilterFactory" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="SecurityManager" ref="securityManager"></property>
		<property name="LoginUrl" value="/doLoginUI.do"></property>
		<!-- 设置请求过滤规则 -->
		<property name="FilterChainDefinitionMap">
			<map>
				<entry key="/bower_components/**" value="anon"></entry>
				<entry key="/build/**" value="anon"></entry>
				<entry key="/dist/**" value="anon"></entry>
				<entry key="/plugins/**" value="anon"></entry>
				<entry key="/user/doLogin.do" value="anon"></entry>
				<entry key="/doLogout.do" value="logout"></entry>
				<!-- 除了以上的资源,其他资源都需要登录认证 -->
				<entry key="/**" value="authc"></entry>
			</map>
		</property>
	</bean>
</beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>CGB-JT-SYS-V1.01</display-name>
  <!-- Shiro中的核心过滤器(负责拦截请求) -->
  <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>
  
  <!-- 配置Spring MVC 前端控制器 -->
  <!-- 注册前端控制器 -->
  <servlet>
       <servlet-name>frontController</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <init-param>
          <param-name>contextConfigLocation</param-name><!-- 这个名字不能随意写 -->
          <param-value>classpath:spring-configs.xml</param-value>
       </init-param> 
       <!--配置servlet在服务器启动时加载(数字越小优先级越高) 
                       配置如下选项以后,tomcat启动时就会初始化这个servlet,
                       这个servlet在初始化时会读取contextConfigLocation
                       参数对应的配置文件.
        -->
       <load-on-startup>1</load-on-startup>
 </servlet>
 <!-- 配置前端控制器映射 -->
 <servlet-mapping>
      <servlet-name>frontController</servlet-name>
      <url-pattern>*.do</url-pattern>
 </servlet-mapping>
 
</web-app>

猜你喜欢

转载自blog.csdn.net/weixin_42867325/article/details/82829457
今日推荐