spring security

在这里插入图片描述

在这里插入图片描述

常用的类
  • FilterChainProxy : 原生的Filter ,,,他会委托给一个指定名字的spring bean执行,这个bean的名字就是springSecurityFilterChain, 他会通过不同的url,将连接转发到不同的SecurityFilterChain上面处理
  • SecurityFilterChain: 就是一系列Filter的集合
  • Authentication : 用户认证的信息
  • AuthenticationManager : 管理怎么去认证,会管理一系列AuthenticationProvider,,遍历的去进行认证
  • AuthenticationProvider : 认证方案的具体实现
  • UserDetailsService : 怎么去加载用户信息,, 常用的是从数据库加载
  • SecurityContextHolder : 认证成功之后存放信息
  • HttpSecurity : 配置这个SecurityFilterChain链条
  • AuthorizeConfigurer : 链条里面有很多filter,,,configurer就是将这些filter归类成configurer,,,比如 httpSecurity配置中formLogin()配置表单登录,就是一个FormLoginConfigurer,比如说处理csrf的也是一个CsrfConfigurer, 它里面会包含相关的filter,,然后将filter放入到 一个filter的集合中,,这个集合在最后build()方法中被构建成一个SecurityFilterChain
代码
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Request {

    private String username;
    private String password;
}


public class Response {


}

认证信息对象:


public interface Authentication {


    Object getPrincipal();

    Object getCredentials();

    boolean isAuthenticated();


    void setAuthenticated(boolean authenticated);
}




public class UsernamePasswordAuthenticationToken implements Authentication{

    private Object principal;
    private Object credentials;

    private boolean authenticated;


    public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        this.principal = principal;
        this.credentials = credentials;
    }

    @Override
    public Object getPrincipal() {
        return principal;
    }

    @Override
    public Object getCredentials() {
        return credentials;
    }

    @Override
    public boolean isAuthenticated() {
        return authenticated;
    }

    @Override
    public void setAuthenticated(boolean authenticated) {

        this.authenticated  = authenticated;
    }
}

认证管理器:

public interface AuthenticationManager {

    Authentication authenticate(Authentication authentication);
}

认证管理器的实现类:

public class ProviderManager implements AuthenticationManager{

    private List<AuthenticationProvider> providers;

    public ProviderManager(List<AuthenticationProvider> providers) {
        this.providers = providers;
    }

    @Override
    public Authentication authenticate(Authentication authentication) {

        for (AuthenticationProvider provider : providers) {
            if (provider.supports(authentication.getClass())) {
                Authentication result = provider.authenticate(authentication);
                if (result != null && result.isAuthenticated()){
                    return result;
                }
            }
        }

        throw new RuntimeException("认证失败");
    }
}

单独的认证管理provider执行者:

public interface AuthenticationProvider {


    boolean supports(Class<?> clazz);

    Authentication authenticate(Authentication authentication);
}

public class DaoAuthenticationProvider implements AuthenticationProvider{
    @Override
    public boolean supports(Class<?> clazz) {

        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(clazz);

    }

    @Override
    public Authentication authenticate(Authentication authentication) {

        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();


        if (username.equals("admin") && password.equals("123")){
            authentication.setAuthenticated(true);
            return authentication;
        }


        throw new RuntimeException("认证失败,用户名错误");

    }
}

过滤器:

public interface Filter {

    void doFilter(Request request, Response response, SecurityFilterChain chain);

}

过滤器链:会挨个的执行里面的过滤器

public class SecurityFilterChain {

    private List<Filter> filters;



    private int currentIndex = 0;


    public SecurityFilterChain(List<Filter> filters) {
        this.filters = filters;
    }



    public void doFilter(Request request,Response response){

        if (currentIndex < filters.size()){

            Filter filter = filters.get(currentIndex);
            System.out.println("执行filter"+filter.getClass().getSimpleName());

            currentIndex+=1;


            filter.doFilter(request,response,this);

        }else{

            System.out.println("finish....");
        }

    }
}

构建过滤器链的对象:HttpSecurity,,会根据DSL语言,去构建多个SecurityFilterChain对象

public class HttpSecurity {


    private List<SecurityConfigurer> configurers = new ArrayList<>();

    private List<Filter> filters = new ArrayList<>();




    public HttpSecurity formLogin(){
        configurers.add(new FormLoginConfigurer());

        return this;
    }


    public HttpSecurity authorize(){
        configurers.add(new AuthorizeConfigurer());
        return this;
    }


    public HttpSecurity addFilter(Filter filter){
        filters.add(filter);
        return this;
    }


    /**
     * 构建HttpSecurityChain
     * @return
     */
    public SecurityFilterChain build(){
        //
        for (SecurityConfigurer configurer : configurers) {
            configurer.init(this);
        }


        for (SecurityConfigurer configurer : configurers) {
            configurer.configure(this);
        }


        return new SecurityFilterChain(filters);
    }

}

configurer配置模块:将一种模块内的filter打包进去:

public interface SecurityConfigurer {

    /**
     *
     * @param http 核心的builder
     */
    void init(HttpSecurity http);


    void configure(HttpSecurity http);

}
public class FormLoginConfigurer implements SecurityConfigurer{
    @Override
    public void init(HttpSecurity http) {
        System.out.println("初始化 formlogin configurer");
    }

    @Override
    public void configure(HttpSecurity http) {

       http.addFilter(new FormLoginFilter());
    }
}
public class AuthorizeConfigurer implements SecurityConfigurer{
    @Override
    public void init(HttpSecurity http) {
        System.out.println("authorize configurer init");
    }

    @Override
    public void configure(HttpSecurity http) {

        http.addFilter(new AuthorizationFilter());
    }
}

每一种configurer都会配置各自的Filter:
比如 FormLoginConfigurer,我就配置了一个FormLoginFilter


public class FormLoginFilter implements Filter{
    @Override
    public void doFilter(Request request, Response response, SecurityFilterChain chain) {
        System.out.println("form login filter");

        chain.doFilter(request,response);
    }
}

public class AuthorizationFilter implements Filter{
    @Override
    public void doFilter(Request request, Response response, SecurityFilterChain chain) {

        System.out.println("authorization filter");

        chain.doFilter(request,response);
    }
}

管理上下文认证信息的threadlocal:

public class SecurityContextHolder {

    private static ThreadLocal<Authentication> CONTEXT_HOLDER = new ThreadLocal<>();


    public static Authentication get(){
        return CONTEXT_HOLDER.get();
    }


    public static void set(Authentication authentication){
        CONTEXT_HOLDER.set(authentication);
    }


    public static void clear(){
        CONTEXT_HOLDER.remove();
    }

}

自定义校验登录的filter:

public class UsernamePasswordAuthenticationFilter implements Filter{

    private AuthenticationManager authenticationManager;

    public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public void doFilter(Request request, Response response, SecurityFilterChain chain) {

        String username = request.getUsername();
        String password = request.getPassword();

        System.out.println("执行登录认证");

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);


        try {
            Authentication auth = authenticationManager.authenticate(usernamePasswordAuthenticationToken);


            SecurityContextHolder.set(auth);

            System.out.println("登录成功");


            chain.doFilter(request,response);
        } catch (Exception e) {
            System.out.println("登录失败");
            throw new RuntimeException(e);
        }

    }
}

测试:

    public static void main(String[] args) {


        HttpSecurity httpSecurity = new HttpSecurity();


        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();

        ProviderManager manager = new ProviderManager(Arrays.asList(daoAuthenticationProvider));

        UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(manager);


        // todo spring security中 Filter排序
        SecurityFilterChain securityFilterChain = httpSecurity.formLogin().authorize()
                .addFilter(filter)
                .build();


        Request request = new Request("admin","123");
        Response response = new Response();

        securityFilterChain.doFilter(request,response);
    }
}

这个spring security的认证流程demo,用到的设计模式:

  • 责任链
  • 门面模式+调度中心 : AuthenticationManager去做认证的时候,根据判断support()是否支持这种认证进行调度
  • 策略模式
  • 构建者模式
  • 策略+模块化 : configurer体系,,FormLoginConfigurer,,,OAuth2LoginConfigurer

公众号:代码源记

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐