天天看點

Spring Security使用(二)Spring Security的基本原理

Spring Security的基本原理

Spring Security的本質就是一個過濾器鍊,擁有很多過濾器

一、檢視源碼

FilterSecurityInterceptor過濾器

是一個方法級的過濾器,基本位于過濾器的最底部

可以在idea中按下兩次shift鍵進行查找,如下圖

Spring Security使用(二)Spring Security的基本原理

源碼

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.web.access.intercept;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;

public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
    private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
    private FilterInvocationSecurityMetadataSource securityMetadataSource;
    private boolean observeOncePerRequest = true;

    public FilterSecurityInterceptor() {
    }

    public void init(FilterConfig arg0) throws ServletException {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        this.invoke(fi);
    }

    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
        this.securityMetadataSource = newSource;
    }

    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        if (fi.getRequest() != null && fi.getRequest().getAttribute("__spring_security_filterSecurityInterceptor_filterApplied") != null && this.observeOncePerRequest) {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } else {
            if (fi.getRequest() != null && this.observeOncePerRequest) {
                fi.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
            }

            InterceptorStatusToken token = super.beforeInvocation(fi);

            try {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            } finally {
                super.finallyInvocation(token);
            }

            super.afterInvocation(token, (Object)null);
        }

    }

    public boolean isObserveOncePerRequest() {
        return this.observeOncePerRequest;
    }

    public void setObserveOncePerRequest(boolean observeOncePerRequest) {
        this.observeOncePerRequest = observeOncePerRequest;
    }
}

           
Spring Security使用(二)Spring Security的基本原理

super.beforeInvocation(fi) 表示檢視之前的 filter 是否通過。

fi.getChain().doFilter(fi.getRequest(), fi.getResponse());表示真正的調用背景的服務。

ExceptionTranslationFilter過濾器

是異常過濾器,用來處理在認證授權過程中抛出的異常

源碼略~

UsernamePasswordAuthenticationFilter

對/login 的 POST 請求做攔截,校驗表單中使用者名,密碼

源碼略~

Spring Security使用(二)Spring Security的基本原理

二、過濾器的加載過程

Spring Security使用(二)Spring Security的基本原理

三、兩個重要的接口

UserDetailsService 接口

當沒有對項目進行任何設定的時候,賬号和密碼是由 Spring Security 定義生成的。而在實際項目中賬号和密碼都是從資料庫中查詢出來的。 是以我們要通過自定義邏輯控制認證邏輯

而當需要自定義控制邏輯時也就是說當我們需要查詢資料庫時,實作UserDetailsService 接口即可

- 建立類繼承UsernamePasswordAuthenticationFilter,重寫三個方法
- 建立類實作UserDetailService,編寫查詢資料過程,傳回User對象,這個User對象是安全架構提供對象
           

PasswordEncoder 接口

通過實作該接口,實作對傳回的User密碼進行加密

執行個體

@Test
    public void test01(){
        // 建立密碼解析器
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        // 對密碼進行加密
        String atguigu = bCryptPasswordEncoder.encode("atguigu");
        // 列印加密之後的資料
        System.out.println("加密之後資料:\t"+atguigu);
        //判斷原字元加密後和加密之前是否比對
        boolean result = bCryptPasswordEncoder.matches("atguigu", atguigu);
        // 列印比較結果
        System.out.println("比較結果:\t"+result);
    }
           

繼續閱讀