SpringSecurity

项目是使用springboot搭建

目录

目录

一、Spring security框架简介

 1、简介

 2、框架原理

 3、框架的核心组件

二、自定义安全配置的加载机制

1、前提 基于自身业务需要

2、WebSecurityConfiguration类

3、AbstractSecurityBuilder类

4、举例说明如何将一个Configurer转换为filter

三、用户登录的验证和授权过程

一、Spring security框架简介


     1、简介
           一个能够为基于Spring的企业应用系统提供声明式的安全訪问控制解决方式的安全框架(简单说是对访问权限进行控制嘛),应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。   spring security的主要核心功能为 认证和授权,所有的架构也是基于这两个核心功能去实现的。

     2、框架原理
     众所周知 想要对对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。

所以springSecurity在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。
对Web资源的保护,就是靠Filter实现的。如下图:在这里插入图片描述
        如下为其主要过滤器  

 

        WebAsyncManagerIntegrationFilter 
        SecurityContextPersistenceFilter 
        HeaderWriterFilter 
        CorsFilter 
        LogoutFilter
        RequestCacheAwareFilter
        SecurityContextHolderAwareRequestFilter
        AnonymousAuthenticationFilter
        SessionManagementFilter
        ExceptionTranslationFilter
        FilterSecurityInterceptor
        UsernamePasswordAuthenticationFilter
        BasicAuthenticationFilter

     3、框架的核心组件
      SecurityContextHolder:提供对SecurityContext的访问
      SecurityContext,:          持有Authentication对象和其他可能需要的信息
      AuthenticationManager  其中可以包含多个AuthenticationProvider
      ProviderManager对象为AuthenticationManager接口的实现类
      AuthenticationProvider 主要用来进行认证操作的类 调用其中的authenticate()方法去进行认证操作
      Authentication:          Spring Security方式的认证主体
      GrantedAuthority:     对认证主题的应用层面的授权,含当前用户的权限信息,通常使用角色表示
      UserDetails:              构建Authentication对象必须的信息,可以自定义,可能需要访问DB得到
      UserDetailsService: 通过username构建UserDetails对象,通过loadUserByUsername根据userName获取UserDetail对象       (可以在这里基于自身业务进行自定义的实现  如通过数据库,xml,缓存获取等)

二、自定义安全配置的加载机制

    1、前提 基于自身业务需要

@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration   //@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
@EnableWebSecurity //要使Spring Security生效,主要是需要配置@EnableWebSecurity注解; (在SpringBoot中,默认的Spring Security就是生效了的,此时的接口都是被保护的,我们需要通过验证才能正常的访问)
@EnableGlobalMethodSecurity(prePostEnabled = true) //Spring Security默认是禁用注解的,要想开启注解,需要在继承WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解,并在该类中将AuthenticationManager定义为Bean。
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 这是必须写法 配合 @EnableGlobalMethodSecurity 实现spring security 开启注解
     */
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 装载BCrypt密码编码器(加密密码)
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 注意这里用的是@Autowired :(通过byType形式,用来给指定的字段或方法注入所需的外部资源)  以此来构建 AuthenticationManager
     */
    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder   //AuthenticationManagerBuilder 用于创建一个 AuthenticationManager,让我能够轻松的实现内存验证、LADP验证、基于JDBC的验证、添加UserDetailsService、添加AuthenticationProvider
                // 设置UserDetailsService
                .userDetailsService(this.userDetailsService)
                // 使用BCrypt进行密码的hash
                .passwordEncoder(passwordEncoder());
    }

    /**
     * 具体实现请求过滤,校验权限 限定发法
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // 由于使用的是JWT,我们这里不需要csrf
                .csrf().disable()
                // wizard  如果注释掉下面  这一行, 由于ConcurrentSessionFilter 在springSecurity过滤器链条中 位于自定义JwtAuthenticationTokenFilter 之前,所以就相当于废掉了jwt自定义的JwtAuthenticationTokenFilter过滤器了
//                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() //wizard 基于token,所以不需要session  如果用jwt加密 这行应该放开
                .authorizeRequests()  // 这里的意思是指通过authorizeRequests()方法来开始请求权限配置。
                .antMatchers( "/index.do").permitAll()
                .antMatchers( "/auth/**").permitAll()
                .antMatchers( "/druid/**").permitAll()
                .antMatchers( "/aliyun/**").permitAll()
                // 允许对于网站静态资源的无授权访问
                .antMatchers(
                            HttpMethod.GET,
                            "/",
                            "/*.html",
                            "/**/*.ico",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js"
                            ).permitAll()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources").permitAll()
                .antMatchers("/images/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/*").permitAll()
                .antMatchers("/configuration/*").permitAll()

                .anyRequest().authenticated();  // 除上面外的所有请求外全部需要鉴权认证
        // wizard  在 UsernamePasswordAuthenticationFilter 前添加 JwtAuthenticationTokenFilter 自定义的过滤器(其实他本身还有很多过滤器,这里只能定义 自定义过滤器的位置)
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
        // 禁用缓存
        httpSecurity.headers().cacheControl();
    }

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }

}

三、用户登录的验证和授权过程


      1、用户一次完整的登录验证和授权,是一个请求经过 层层拦截器从而实现权限控制,整个web端配置为DelegatingFilterProxy(springSecurity的委托过滤其代理类 ),它并不实现真正的过滤,而是所有过滤器链的代理类,真正执行拦截处理的是由spring 容器管理的个个filter bean组成的filterChain.

调用实际的FilterChainProxy 的doFilterInternal()方法 去获取所有的拦截器并进行过滤处理如下是DelegatingFilterProxy的doFilter()方法


public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Filter delegateToUse = this.delegate;
        if(delegateToUse == null) {
            Object var5 = this.delegateMonitor;
            synchronized(this.delegateMonitor) {
                delegateToUse = this.delegate;
                if(delegateToUse == null) {
                    WebApplicationContext wac = this.findWebApplicationContext();
                    if(wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
                    }
 
                    delegateToUse = this.initDelegate(wac);
                }
 
                this.delegate = delegateToUse;
            }
        }
 
//调用实际的FilterChainProxy 的doFilterInternal()方法 去获取所有的拦截器并进行过滤处理
        this.invokeDelegate(delegateToUse, request, response, filterChain);
    }

调用实际的FilterChainProxy 的doFilter()方法 去获取所有的拦截器并进行过滤处理。

2、FilterChainProxy类

    最终调用FilterChainProxy 的doFilterInternal()方法,获取所有的过滤器实例

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
        if(clearContext) {
            try {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
                //doFilter 调用doFilterInternal方法
                this.doFilterInternal(request, response, chain);
            } finally {
                SecurityContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        } else {
            this.doFilterInternal(request, response, chain);
        }
 
    }
 
    private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FirewalledRequest fwRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);
        HttpServletResponse fwResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);
         //过去所有的过滤器
        List<Filter> filters = this.getFilters((HttpServletRequest)fwRequest);
        if(filters != null && filters.size() != 0) {
            FilterChainProxy.VirtualFilterChain vfc = new FilterChainProxy.VirtualFilterChain(fwRequest, chain, filters);
            vfc.doFilter(fwRequest, fwResponse);
        } else {
            if(logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(fwRequest) + (filters == null?" has no matching filters":" has an empty filter list"));
            }
 
            fwRequest.reset();
            chain.doFilter(fwRequest, fwResponse);
        }
    }
 
 
  private List<Filter> getFilters(HttpServletRequest request) {
       //遍历所有的matcher类 如果支持就继续获取
        Iterator var2 = this.filterChains.iterator();
 
        SecurityFilterChain chain;
        do {
            if(!var2.hasNext()) {
                return null;
            }
 
            chain = (SecurityFilterChain)var2.next();
        } while(!chain.matches(request));
        //后去匹配中的所有过滤器
        return chain.getFilters();
    }

如上 其实是获取到本次请求的所有filter 并安装指定顺序进行执行doFilter()方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值