시로 권한 관리 프레임 워크 (III) : 초기화 과정 시로 권한 필터 및 구현 원리

Benpian 필터 초기화 프로세스 및 구현 원리 일련 시로 시로 세 번째이다. 시로 URL 기반 권한 제어는 우리의 주입에서이 여기 필터에 의해 달성된다 ShiroFilterFactoryBean이 시작 시로의 원칙의 소스 코드 검색 필터의 실현을보고하기 시작했다.


초기화 과정

ShiroFilterFactoryBean은 다음 봄 초기화 시간으로 getObject의 ShiroFilterFactoryBean은 () ShiroFilterFactoryBean 동안 초기화 일련의 작업을 수행하는이 시점에서, 인스턴스를 가져옵니다 호출 바인딩의 FactoryBean 인터페이스를 깨달았다.

추가의 FactoryBean 도입 및 구현 정보도 일기를 썼다 : https://www.guitu18.com/post/2019/04/28/33.html

으로 getObject에서 ()으로 createInstance ()는, 초기화와 관련된 일 현재, 주석 코드 스티커를 제공하고 관련 코드를 확인 호출합니다.

    protected AbstractShiroFilter createInstance() throws Exception {
        SecurityManager securityManager = getSecurityManager();
        FilterChainManager manager = createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

첫째, 거기에 우리는이 시로의 핵심 요소임을 다시 한번 강조하고, 잘 ShiroConfig 시큐리티 매니저의 주입의 매개 변수를 얻을. 그럼 FilterChainManager을 만들고 이름이 클래스를 필터 체인의 구현 및 동작을 관리하는 데 사용되는 우리의 작성 방법을 살펴 createFilterChainManager ().

    protected FilterChainManager createFilterChainManager() {
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        Map<String, Filter> defaultFilters = manager.getFilters();
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }
        Map<String, Filter> filters = getFilters();
        if (!CollectionUtils.isEmpty(filters)) {
            for (Map.Entry<String, Filter> entry : filters.entrySet()) {
                String name = entry.getKey();
                Filter filter = entry.getValue();
                applyGlobalPropertiesIfNecessary(filter);
                if (filter instanceof Nameable) {
                    ((Nameable) filter).setName(name);
                }
                manager.addFilter(name, filter, false);
            }
        }
        Map<String, String> chains = getFilterChainDefinitionMap();
        if (!CollectionUtils.isEmpty(chains)) {
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                manager.createChain(url, chainDefinition);
            }
        }
        return manager;
    }

새로운 DefaultFilterChainManager의 첫 번째 단계는, 필터 및 방법 filterChains 두 멤버 변수의 구축 시로 호 addDefaultFilters 일부 내장 필터를 추가하기 전에, 삽입을 유지하기의 LinkedHashMap 위해 초기화된다 ().

    public DefaultFilterChainManager() {
        this.filters = new LinkedHashMap<String, Filter>();
        this.filterChains = new LinkedHashMap<String, NamedFilterList>();
        addDefaultFilters(false);
    }
    protected void addDefaultFilters(boolean init) {
        for (DefaultFilter defaultFilter : DefaultFilter.values()) {
            addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
        }
    }

여기 시로의 모든 인스턴스의 열거 목록 필터가 내장.

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
}

상기 코드가 위 열거 된 타입은 어떤 필터가 이러한 필터는 단지 실행과 체인 필터, 각 필터에 첨가 여기 초기화 한 내장 시로 시로 내지 제 정확하게 대응 생략 다른 기능을 가지고, 우리는 사실 만이 앞을 사용했다.

IMG

DefaultFilterChainManager 초기화가 각각 기본 필터를 통과, 완료되고 applyGlobalPropertiesIfNecessary를 호출 한 후 돌아 가기 이전 단계로, () 일부 글로벌 속성을 설정합니다.

    private void applyGlobalPropertiesIfNecessary(Filter filter) {
        applyLoginUrlIfNecessary(filter);
        applySuccessUrlIfNecessary(filter);
        applyUnauthorizedUrlIfNecessary(filter);
    }

이 방법은 세 가지 방법을 호출에서, 세 가지 방법이 같은 논리이다 loginUrl,을 successURL 및 unauthorizedUrl을 설정, 우리가 처음 applyLoginUrlIfNecessary 볼 것이다 ().

    private void applyLoginUrlIfNecessary(Filter filter) {
        String loginUrl = getLoginUrl();
        if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) {
            AccessControlFilter acFilter = (AccessControlFilter) filter;
            String existingLoginUrl = acFilter.getLoginUrl();
            if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) {
                acFilter.setLoginUrl(loginUrl);
            }
        }
    }

우리가 loginUrl를 구성한 경우이 loginUrl을 설정하는 방법 이름임을 참조 후, 우리는 기본 loginUrl을 AccessControlFilter합니다 설정 값을 대체, 기본값은 loginUrl입니다 /login.jsp. 같은 이유로 후자의 두 가지 방법은, 우리의 교체의 모든 매개 변수를 설정할 수 있지만 세 번째 인증 실패 점프 URL 기본 값은 null입니다.

돌아가 계속,지도 <문자열, 필터> 필터 =의 getFilters (); 여기에 우리의 사용자 정의 필터를 얻는 것입니다, 기본은 우리가 사용자 정의 필터를 구성 할 경우, 다음에 추가, 비어 필터입니다. 지금까지 시로 필터가 내장 된 필터와 필터 우리의 모든 구성에 포함되어 있습니다.

다음으로, filterChainDefinitionMap을 통과, 이것은 우리가 ShiroConfig에 차단 규칙 구성을 주입 filterChainDefinitionMap 것입니다. 여기에서 우리의 구성에 따라 필터 체인을 실행 필터 규칙을 생성 만드는 것이다.

    public void createChain(String chainName, String chainDefinition) {
        String[] filterTokens = splitChainDefinition(chainDefinition);
        for (String token : filterTokens) {
            String[] nameConfigPair = toNameConfigPair(token);
            addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
        }
    }

: chainName 우리가 필터 경로를 구성하고, chainDefinition은 일반적으로 우리가 같은 모든 하나 하나 개의 구성에있는 경로 해당하는 필터입니다 filterMap.put("/login", "anon");,하지만 우리는 경로가 실제로 전달하여 필터링 할 수 있다는 사실을 알고 길을보고 ["filter1","filter2"...]구성의 복수를 필터. 다음은 구성 여과 필터 맵핑에 기초하여 상기 필터 체인 실행 경로를 구성하는 단계에 의해 단계 일 것이다.

    public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
        Filter filter = getFilter(filterName);
        applyChainConfig(chainName, filter, chainSpecificFilterConfig);
        NamedFilterList chain = ensureChain(chainName);
        chain.add(filter);
    }

시작 필터있어서 FILTERNAME는 해당 필터를 획득하고 ensureChain ()가 chainName 따라 NamedFilterList filterChains 취득을 시작한다 만들고 나서 반환 filterChains 첨가 얻지.

    protected NamedFilterList ensureChain(String chainName) {
        NamedFilterList chain = getChain(chainName);
        if (chain == null) {
            chain = new SimpleNamedFilterList(chainName);
            this.filterChains.put(chainName, chain);
        }
        return chain;
    }

필터와 필터 경로가 많은 관계로 하나이기 때문에 (가), NamedFilterList는 속성이 목록 <필터>라는 이름이 실제로 반환이 이름은 필터 경로를 저장 ensureChain 있도록 목록은 우리의 구성의 필터가 보유하고있다. 필터에서 패스 필터와 같은 여과 맵핑뿐만 아니라 초기화 이에 얻은 후 NamedFilterList했다.

따라서, 완료된 것으로 간주 실행에으로 createInstance createFilterChainManager는 () ()는 인스턴스 FilterChainManager를 반환합니다. 그런 다음이 주사 후 필터의 체인 PathMatchingFilterChainResolver FilterChainManager은 파서를 행한다.

메소드 PathMatchingFilterChainResolver 많이, 가장 중요한 것은 getChain () 방법이다.

    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }
        String requestURI = getPathWithinApplication(request);
        for (String pathPattern : filterChainManager.getChainNames()) {
            if (pathMatches(pathPattern, requestURI)) {
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }
        return null;
    }

이 두 가지 매개 변수 참조의 ServletRequest와 ServletResponse를 매개 변수는 특히 따뜻한 느낌이 아니라, 익숙한 것들 마침내 하나가 요청에 대한 확신을 가지고 말할 수있는 점을 보았다. 예, 우리는 요청의 URL에 기초하여 정합 필터 체인 패스 필터를 수행하는 필터에 대응하는 정합 필터를 리턴하는 각각의 요청에있어서의 서버를 호출한다.

이 방법 filterChainManager.getChainNames ()는 체인 구성 우리는 우리의 구성에서 발생하는 동일한 쇄 시퀀스를 순차적으로 행한다 생성하도록 배치 된 필터에 따라 수집 실행 경로를 반환. 우리가 볼 수있는 전술에서하는의 LinkedHashMap 것이다 filterChains 생성자 DefaultFilterChainManager에 초기화됩니다. 그래서 당신은 필터 경로의 첫 경기 인 경우 다시 내 첫 번째 게시물 시로 노트의 진실이다에 필터의 큰 범위를 언급 할 /**필터 뒤에 결코 일치가 아니라고.


원리 필터

그래서이 getChain () 어떻게이라고? 이 요청이 책임 체인 필터 톰캣, 시리즈의 형태로 톰캣 전화를 도착 때, 이상 확실히 톰캣에서 HTTP 요청이기 때문에, OncePerRequestFilter 많은 필터 중 하나입니다. 그것은 doFilter () 메소드는 doFilterInternal () 자신의 추상적 인 방법은이 방법에서의 서브 클래스 AbstractShiroFilter에 구현되어 전화를 구현합니다.

IMG

PathMatchingFilterChainResolver.getChain는 () 호출 doFilterInternal 호출 된 단계에 의해 단계 ()이다.

    protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, 
                                    final FilterChain chain) throws ServletException, IOException {
            final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
            final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
            final Subject subject = createSubject(request, response);
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    updateSessionLastAccessTime(request, response);
                    executeChain(request, response, chain);
                    return null;
                }
            });
    }

여기서 제 포착 필터를 획득하고 실행.

    protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
            throws IOException, ServletException {
        FilterChain chain = getExecutionChain(request, response, origChain);
        chain.doFilter(request, response);
    }

다음과 같이 필터를 가져옵니다.

    protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
        FilterChain chain = origChain;
        FilterChainResolver resolver = getFilterChainResolver();
        if (resolver == null) {
            return origChain;
        }
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            chain = resolved;
        } else {
        }
        return chain;
    }

getFilterChainResolver ()에 정합 필터 얻는다 () 상기의 연쇄 PathMatchingFilterChainResolver 파서를 수행하는 필터를 구비하고 getChain 호출하는 필터가 마침내 executeChain ()를 행한다.


시작 주소 : https://www.guitu18.com/post/2019/08/01/45.html

개요

우리의 구성에서 시로 프레임 ShiroFilterFactoryBean 초기화를 많이 할 초기화, 우리는 필터 체인의 실행에 필터를 해당하는 필터 규칙을 구성하는 단계를 추가합니다, 실행 체인은 궁극적으로 실행 체인 파서에 넣고 . 요청이 Tomcat을 도착하면, 프로세스가 톰캣의 책임 필터 체인에 의해 수행, 정의 최종 시로 AbstractShiroFilter.doFilter는 () 실행, 다음 체인 검색에 갈 것이다, 실행 체인을 통해 파서 get 및 여과를 파서를 수행 따라서 권한에 기초하여, URL 필터링을 달성 수행한다.

이 문서의 끝은,이 시로 시로 필터 초기화 및 실행 프로세스를 이해하기 쉽게 많은 봄 소스 시로 소스에 비해 무엇의 이해에 광원으로 간주 될 수있다, 그래서 봄 주위에 없습니다. 나는 소스 코드를 볼 때마다, 나는이 느낌이 특히 강한 경우에 특히 스프링 소스를보고,이 느낌 아래에 있습니다 :

IMG

우리는 프레임을 구성하고 전화, 항상 약간의 물에 떠있는 것, 아무 문제, 당신은 바닥이 괴물이 무엇인지 알 수 없다. 더 나은 프레임 패키지는 적게, 더 많은 숨겨진 부분을 등장.

예를 SpringBoot를 들어, 방법의 주요 메소드는, 그것을있는 application.properties 프로젝트, web.xml 파일을 시작 할 수 있습니다 SpringMVC를 왜하는 방법에 URL에서 @RequestMapping 호출을 달성 할 수 있어야한다; 왜 시로 @RequiresPermissions을 달성 할 수있을 만하면 메소드 레벨 액세스 제어.

더 당신은 더 적은 당신이 알고, 이것은 매우 모순하지만 실제 느낌 느낌 배운다. 연구를 말하지 말라, 최후의 수단으로 위의 다음 단계는 시간, 그냥 때문에 프로젝트 데이터베이스 최적화 관련 문제의 최근 만남의 결정 MySQL을 참조 가고 싶어 할, 액세스 제어를 작성합니다.

추천

출처www.cnblogs.com/guitu18/p/11315195.html