Spring Security使用基础
  I6B6oQKIoM4W 2023年11月17日 29 0

不论是自己写还是使用某些权限框架,他们的很多处理逻辑都是相似的,下图展示了对资源访问的常规处理逻辑

Spring Security使用基础_Spring

我们跟着下面的问题来学习如何使用Spring Security框架

  1. 用户访问资源时,某些资源不需要登录都可以访问,那么如何配置?
  2. 如何判断用户是否处于已登录状态?
  3. 没有登录时,可以有哪些处理方式?
  4. 如何从请求中解析出需要的登录信息?
  5. 如何获取外部存储的用户信息?
  6. 在哪里如何做登录认证?
  7. 如果登录失败了,都可以怎么进行处理?
  8. 如果登录成功了,都可以怎么进行处理?
  9. 有哪些途径可以对权限进行校验?
  10. 如果权限不足,都可以进行怎么样的处理?

在解答以上问题前,我们先了解下如何注册Filter和Servlet


1、Java web中注册Filter和Servlet

方法1:web.xml

在web.xml文件中配置Filter和Servlet可以将自定义的Filter和Servlet添加到调用链里面

<?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_3_0.xsd"
         id="WebApp_ID" version="3.0">
    <!-- 注册Filter -->
    <filter>
        <filter-name>filter-name</filter-name>
        <filter-class>com.demo.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter-name</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- 注册Servlet-->
    <servlet>
        <servlet-name>servlet-name</servlet-name>
        <servlet-class>com.demo.MyServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>servlet-name</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

方法2:注解注册

@WebFilter(
  filterName = "my-fileter",
  urlPatterns = "/*"
)
public class MyFilter implements Filter {
	
}

@WebServlet(
  name = "my-servlet",
  urlPatterns = "/*"
)
public class MyServlet extends HttpServlet  {
	
}

方法2:ServletContext注册

servletContext.addServlet("servlet-name",servlet) ;
servletContext.addFilter("filter-name",filter) ;


2、Spring web中注册Filter

在Java web中我们有多种方式来注册Filter,但是我们在使用Spring框架的时候,如果还是通过这种方式来使用,似乎就不能很好的利用IOC的特性了,所以在spring web中设计了代理类:DelegatingFilterProxy

DelegatingFilterProxy自身就是一个Filter类型,在其内部通过从Spring 容器中获取Filter类型的Bean,并完成对其的委派实例的执行;

在使用的时候,值需要将DelegatingFilterProxy注册到Servlet容器中即可,例如:

<filter>
	<filter-name>filterProxy</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>filterProxy</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>


3、Springboot中注册Filter和Servlet

在讲具体的注册方法时,我们先看看Springboot是如何初始化Servlet容器的。

Servlet Contaier启动

  1. META-INF/spring.factories中加载所有BootstrapRegistryInitializer类型并保存
  2. META-INF/spring.factories中加载所有ApplicationContextInitializer类型并保存
  3. META-INF/spring.factories中加载所有ApplicationListener类型并保存
  4. 创建DefaultBootstrapContext实例,并作为参数调用所有保存的BootstrapRegistryInitializer实例
  5. 创建AnnotationConfigServletWebServerApplicationContext实例对象
  6. 使用applicationContext作为参数调用保存的每个ApplicationContextInitializer实例对象
  7. 从IOC中获取ServletWebServerFactory类似实例对象
  8. 从BeanFactory中查询ServletContextInitializer类型的实例,主要类型有
  • ServletRegistrationBean类型实例
  • FilterRegistrationBean类型实例
  • DelegatingFilterProxyRegistrationBean类型实例
  • ServletListenerRegistrationBean类型实例
  • 其他ServletContextInitializer实例
  1. 使用ServletContextInitializer类型的集合对象作为参数,调用ServletWebServerFactory类型实例的getWebServer方法来创建web服务器在这个过程中ServletContextInitializer实例将会被回调
  2. 自此Servlet容器的启动过程完成,接下来可以接收外部请求了


从上面的流程可见,在Tomcat启动的过程中,只要能够将ServletContainerInitializer类型的实例传递给Servlet容器,那么在容器的启动过程中会将ServletContext作为参数进行回调,这样在回调的时候,通过ServletContext的接口就可以动态的添加Servlet了

Spring Security使用基础_Spring_02

这里的DispatcherServletRegistrationBean和DelegatingFilterProxyRegistrationBean需要注意下,这两个都是springboot提供的

  • DispatcherServletRegistrationBean:该类型的实例对象在DispatcherServletAutoConfiguration配置类中被创建,其目的就是自动注册DispatcherServlet实例,从而完成SpringMVC框架的集成
  • DelegatingFilterProxyRegistrationBean:该类型的实例对象在SecurityFilterAutoConfiguration配置类中被创建,并使用“springSecurityFilterChain”作为参数进行实例化,目的是集成Spring Security框架。 其内部从IOC中找出名为springSecurityFilterChain的Bean,并通过DelegatingFilterProxy进行封装返回(也就是最终添加到Servlet容器中的是DelegatingFilterProxy实例对象)。


方法1:使用@ServletComponentScan

创建Filter或Servlet等组件的实例,并添加@WebServlet、@WebFilter、@WebListener注解,然后在@Configuration配置类上添加@ServletComponentScan来扫描Servlet组件进行注册。

@Configuration
@ServletComponentScan(basePackages = {"com.demo"})
public class Configuration {
  
}

方法2:使用RegistrationBean子类进行注册

@Bean
public ServletRegistrationBean regServlet() {
  ServletRegistrationBean myServlet= new ServletRegistrationBean();
  myServlet.addUrlMappings("/servlet");
  myServlet.setServlet(new MyServlet());
  return myServlet;
}

@Bean
public FilterRegistrationBean regFilter() {
  FilterRegistrationBean myFilter = new FilterRegistrationBean();
  myFilter.addUrlPatterns("/*");
  myFilter.setFilter(new MyFilter ());
  return myFilter ;
}

@Bean
public ServletListenerRegistrationBean<MySessionListener> regServletListener() {
  ServletListenerRegistrationBean<MySessionListener> mySessionListener= new ServletListenerRegistrationBean<MySessionListener>();
  mySessionListener.setListener(new MySessionListener());
  return mySessionListener;
}

//注意:这是SpringSecurity的集成方式
@Bean
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration() {
	DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
			"springSecurityFilterChain");
	registration.setOrder(100));
	return registration;
}


4、SpringSecurity的运行原理

上面讲述了如何将Filter等实例对象注册到Servlet容器中,下面看下Springboot中几个Filter类型

Spring Security使用基础_Spring Securty_03

在SpringSecurity中会创建名为springSecurityFilterChain的FilterChainProxy实例对象,该对象中包含了一个或多个SecurityFilterChain实例对象,每个SecurityFilterChain实例对象包含了一个或多个用于执行权限控制的Filter实例对象。

springSecurityFilterChain则通过DelegatingFilterProxyRegistrationBean被自动的添加到Servlet容器中,在上面的内容中已经有说明。

Spring Security的逻辑架构图

Spring Security使用基础_Spring_04


知晓以上的基础内容后,我们现在可以来回答最开始提出的一些问题了,具体如何,请看下回分解。





【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月17日 0

暂无评论

推荐阅读
I6B6oQKIoM4W