JavaEE安全框架源码剖析与整合-Spring Security篇

安全框架简介

javaEE生态中,关于安全的框架主要有两种,Shiro和SpringSecurity,两者之间区别还有很大,Shiro是一个轻量级框架,可定制化程度较高,相对来说使用比较灵活,新手配置起来比较复杂,而SpringSecurity是Spring生态系列的顶级框架,跟Springboot天然集成,整合起来最容易,所以就先学习SpringSecurity的简单整合和使用

SpringSecurity整合

项目引入Spring Security依赖

第一步先导入SpringSecurtiy的pom依赖,以及跟thymeleaf的整合包

  <!--security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>

自定义Security核心配置类

WebSecurityConfigurerAdapter是SpringSecurity的核心配置类,Spring的最大的特点就是AOP,面向切面编程,所以在不改变原来的代码上,直接注入一个bean,从而来使用框架,所以这里创建一个配置类SecurityConfig继承自WebSecurityConfigurerAdapter,然后项目SpringBoot就天然无缝集成了SpringSecurity

package com.zjy.config.securityconfig;

import com.zjy.service.security.CustomUserService;
import com.zjy.utils.MD5Util;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * Describe: security 配置
 */
@Configuration
//@EnableWebSecurity
//AOP : 拦截器
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Bean
    UserDetailsService customUserService(){
        return new CustomUserService();
    }

    /**
     *  配置认证方式
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserService())
                //启动密码MD5加密
                .passwordEncoder(new PasswordEncoder() {
            MD5Util md5Util = new MD5Util();
            @Override
            public String encode(CharSequence rawPassword) {
                return md5Util.encode((String)rawPassword);
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return encodedPassword.equals(md5Util.encode((String)rawPassword));
            }
        });
    }

    /**
     *  配置授权规则
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/index").hasAnyRole("USER","ADMIN")
                .antMatchers("/manager").hasRole("ADMIN")
                .antMatchers("/staff").hasRole("USER")
                .and()
                //loginPage和logoutUrl都是post请求
                .formLogin().loginPage("/login_register").failureUrl("/login_register?error").defaultSuccessUrl("/faceCheck")
                .and()
                .logout().logoutUrl("/logout").logoutSuccessUrl("/login_register");
//        http.csrf().disable();

        //没有权限默认会到登录页面
//        http.formLogin();
    }
}

这里有个细节要格外注意一下,在SpringBoot2.1.5以后,SpringSecurtity5.0+之后的新版本中增加了很多的加密方式,存在密码加密编码问题,没有配置这个可以会出现问题
然后就是http.formLogin(),SpringSecurity集成页面,没有权限的时候会默认跳转到登录页面,账号和密码在application.propertis的配置文件中配置

spring.sercurity.user.name=admin
spring.sercurity.user.password=123456

忽略拦截

实现忽略拦截只需在上面的类中注入一个bean,并重写源码默认规则

      /**
     * 忽略拦截
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置拦截忽略url - 会直接过滤该url - 将不会经过Spring Security过滤器链
        web.ignoring().antMatchers("/getUserInfo");
        // 设置拦截忽略文件夹,可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**");
    }

登录业务

    public UserDetails loadUserByUsername(String phone) {

        User user = userRepository.findByPhone(phone);
        if(user == null){
            throw new UsernameNotFoundException("用户不存在");
        }

        List<SimpleGrantedAuthority> authorities = new ArrayList<>();

        for(Role role : user.getRoles()){
            authorities.add(new SimpleGrantedAuthority(role.getName()));
            System.out.println(role.getName());
        }
        return new org.springframework.security.core.userdetails.User(user.getPhone(), user.getPassword(), authorities);
    }

SpringSecurity源码剖析

说了这么多,其实一切都在源码中,如过会看源码的话,这些配置都不是问题,下面简单来说下,SpringSecurity中主要的类
记住几个类:
WebSecurityConfigurerAdapter 自定义Security策略
AuthenticationManagerBuilder: 自定义认证策略
@EnableWebSecurity: 开启WebSecurity模式
Spring Security的两个主要目标是“认证Authentication”和”授权Authorization“(访问控制),这个概念在所有的安全框架中是互通的
WebSecurityConfigurerAdapter类中有以下方法:
继承的所有方法
在 WebSecurityConfigurerAdapter 这个类里面可以完成上述流程图的所有配置,主要使用就是继承上述方法

Spring Security 过滤器链

SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链。现在对这条过滤器链的各个进行说明:
WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。

SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将 SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将 SecurityContextHolder 中的信息清除,例如在Session中维护一个用户的安全信息就是这个过滤器处理的。

HeaderWriterFilter:用于将头信息加入响应中。

CsrfFilter:用于处理跨站请求伪造。

LogoutFilter:用于处理退出登录。

UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的usernameParameter 和 passwordParameter 两个参数的值进行修改。

DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

BasicAuthenticationFilter:检测和处理 http basic 认证。

RequestCacheAwareFilter:用来处理请求的缓存。

SecurityContextHolderAwareRequestFilter:主要是包装请求对象request。

AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。

SessionManagementFilter:管理 session 的过滤器

ExceptionTranslationFilter:处理 AccessDeniedException 和 AuthenticationException 异常。

FilterSecurityInterceptor:可以看做过滤器链的出口。

RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

SpringSecurity 流程图

先来看下面一个 Spring Security 执行流程图,只要把 SpringSecurity 的执行过程弄明白了,这个框架就会变得很简单:
在这里插入图片描述
流程说明

客户端发起一个请求,进入 Security 过滤器链。

当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到 logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出路径则直接进入下一个过滤器。

当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler 登录成功处理器处理,如果不是登录请求则不进入该过滤器。

当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器处理。

总结

步骤:
项目引入Spring Security依赖
自定义Security核心配置类继承WebSecurityConfigurerAdapter
账号密码配置
登录处理
忽略拦截

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值