По умолчанию фильтры не поддерживают исключение определенного шаблона URL-адреса: всякий раз, когда вы определяете шаблон URL-адреса для фильтра, любой запрос, соответствующий этому шаблону, обрабатывается фильтром без исключений.
Самый простой способ исключения URL-адресов из фильтра — это сопоставить фильтр с очень специфическим шаблоном. Это выполнимо, когда это делается на ранних стадиях разработки, однако это может быть трудоемким процессом, если вы изменяете шаблон URL существующего фильтра в производственной среде, так как вам нужно переназначить все существующие URL-адреса сервлетов для достижения вашей цели.
В этом руководстве мы покажем, как программно добавить функцию исключения в существующий фильтр.
1- Пользовательский фильтр
Пользовательский фильтр — это фильтр, которым вы можете управлять. т.е. у вас есть все права на изменение его исходного кода.
Предположим, у нас есть существующее веб-приложение, которое аутентифицирует запросы пользователей через LDAP. Все запросы сервлета проходят через LDAPAuthenticationFilter, который отображается в / * следующим образом:
|
1
2
3
4
5
6
7
8
|
<filter> <filter-name>LDAPAuthenticationFilter</filter-name> <filter-class>com.programmer.gate.filters.LDAPAuthenticationFilter</filter-class></filter><filter-mapping> <filter-name>LDAPAuthenticationFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping> |
Наш фильтр просто аутентифицирует запрос и впоследствии вызывает chain.doFilter () :
LDAPAuthenticationFilter.java
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.programmer.gate.filters; 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 javax.servlet.http.HttpServletRequest; public class LDAPAuthenticationFilter implements Filter{ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // Authenticate the request through LDAP System.out.println("Authenticating the request through LDAP"); // Forward the request to the next filter or servlet in the chain. chain.doFilter(req, resp); } public void init(FilterConfig filterConfig) throws ServletException { } public void destroy() { // TODO Auto-generated method stub }} |
Теперь предположим, что мы хотим создать сервлет, который требует простой аутентификации базы данных и не должен проходить через LDAP. Первым делом мы думаем об этом, чтобы создать новый фильтр и сопоставить его с конкретным шаблоном URL нового сервлета.
Поэтому мы создаем новый фильтр с именем DatabaseAuthenticationFilter, который просто аутентифицирует запрос через базу данных и впоследствии вызывает chain.doFilter () :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package com.programmer.gate.filters; 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; public class DatabaseAuthenticationFilter implements Filter{ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // Authenticate the request through database then forward the request to the next filter or servlet in the chain System.out.println("Authenticating the request through database"); chain.doFilter(req, resp); } public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } public void destroy() { // TODO Auto-generated method stub }} |
Мы определяем наш фильтр в файле web.xml для обработки только определенных URL-адресов, начинающихся с / DatabaseAuthenticatedServlet :
|
1
2
3
4
5
6
7
8
|
<filter> <filter-name>DatabaseAuthenticationFilter</filter-name> <filter-class>com.programmer.gate.filters.DatabaseAuthenticationFilter</filter-class></filter><filter-mapping> <filter-name>DatabaseAuthenticationFilter</filter-name> <url-pattern>/DatabaseAuthenticatedServlet/*</url-pattern></filter-mapping> |
Проблема здесь в том, что запросы типа / DatabaseAuthenticatedServlet также будут соответствовать шаблону корневого URL «/ *», т.е. наш запрос будет проходить через 2 процесса аутентификации: LDAP и Database, порядок зависит от того, какой фильтр определен первым в web.xml .
Чтобы решить эту проблему, нам нужно изменить LDAPAuthenticationFilter, чтобы он исключал URL-адреса, начинающиеся с / DatabaseAuthenticatedServlet. Обычно люди статически проверяют URL-адрес сервлета запроса внутри метода doFilter () и просто обходят процесс аутентификации при его обнаружении.
Здесь мы делаем еще один шаг и внедряем более динамичное решение, которое позволяет нам управлять исключенными URL-адресами через web.xml .
Ниже приведены шаги для добавления функции исключения в LDAPAuthenticationFilter :
- Добавьте новое поле с именем exclusiveUrls типа List <String> :
1
privateList excludedUrls; - Внутри метода init () считайте атрибут конфигурации с именем selectedUrls, используя FilterConfig, атрибут должен разделяться запятыми, чтобы мы исключали столько URL-адресов, сколько нам нужно.
1234
publicvoidinit(FilterConfig filterConfig)throwsServletException {String excludePattern = filterConfig.getInitParameter("excludedUrls");excludedUrls = Arrays.asList(excludePattern.split(","));} - Измените doFilter () , чтобы проверить, принадлежит ли запрашиваемый URL-адрес списку предварительно определенных исключенных URL-адресов, если это так, то просто перенаправьте запрос следующему фильтру или сервлету в цепочке, иначе сделайте логику аутентификации.
0102030405060708091011121314
publicvoiddoFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throwsIOException, ServletException {String path = ((HttpServletRequest) req).getServletPath();if(!excludedUrls.contains(path)){// Authenticate the request through LDAPSystem.out.println("Authenticating the request through LDAP");}// Forward the request to the next filter or servlet in the chain.chain.doFilter(req, resp);} - Теперь внутри web.xml вы можете контролировать, какой URL исключать из аутентификации LDAP без единого изменения кода:
123456789
<filter><filter-name>LDAPAuthenticationFilter</filter-name><filter-class>com.programmer.gate.filters.LDAPAuthenticationFilter</filter-class><init-param><param-name>excludedUrls</param-name><!-- Comma separated list of excluded servlets --><param-value>/DatabaseAuthenticatedServlet,/UnAuthenticatedServlet</param-value></init-param></filter>
Вот так выглядит LDAPAuthenticationFilter после добавления функции исключения:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
package com.programmer.gate.filters; import java.io.IOException;import java.util.Arrays;import java.util.List; 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 javax.servlet.http.HttpServletRequest; public class LDAPAuthenticationFilter implements Filter{ private List excludedUrls; public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { String path = ((HttpServletRequest) req).getServletPath(); if(!excludedUrls.contains(path)) { // Authenticate the request through LDAP System.out.println("Authenticating the request through LDAP"); } // Forward the request to the next filter or servlet in the chain. chain.doFilter(req, resp); } public void init(FilterConfig filterConfig) throws ServletException { String excludePattern = filterConfig.getInitParameter("excludedUrls"); excludedUrls = Arrays.asList(excludePattern.split(",")); } public void destroy() { // TODO Auto-generated method stub }} |
2- Сторонний фильтр
Сторонние фильтры — это фильтры, которыми вы не можете управлять. то есть вы не можете изменить их исходный код.
В этом разделе мы немного изменим наш пример и используем аутентификацию CAS вместо LDAP. Вот как мы определяем наш фильтр аутентификации CAS в web.xml :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
<filter> <filter-name>CAS Authentication Filter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> </init-param> <init-param> <param-name>serverName</param-name> <param-value>localhost</param-value> </init-param></filter><filter-mapping> <filter-name>CAS Authentication Filter</filter-name> <url-pattern>/*</url-pattern></filter-mapping> |
Аутентификация CAS выполняется через стороннюю библиотеку, теперь для поддержки аутентификации базы данных мы не можем изменять исходный код CAS, как мы это делали в предыдущем примере с LDAP.
Решение для исключения URL-адресов из стороннего фильтра состоит в том, чтобы обернуть его новым настраиваемым фильтром, который просто добавляет функцию исключения и делегирует логику фильтра для обернутого класса.
Ниже приведены шаги для добавления функции исключения из к аутентификации CAS:
- Создайте новый фильтр с именем CASCustomAuthenticationFilter следующим образом:
0102030405060708091011121314151617181920212223242526272829303132
publicclassCASCustomAuthenticationFilterimplementsFilter{privateAuthenticationFilter casAuthenticationFilter =newAuthenticationFilter();privateList excludedUrls;publicvoiddoFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throwsIOException, ServletException {String path = ((HttpServletRequest) req).getServletPath();if(!excludedUrls.contains(path)){// Authenticate the request through CAScasAuthenticationFilter.doFilter(req,resp,chain);}// Forward the request to the next filter or servlet in the chain.chain.doFilter(req, resp);}publicvoidinit(FilterConfig arg0)throwsServletException {String excludePattern = filterConfig.getInitParameter("excludedUrls");excludedUrls = Arrays.asList(excludePattern.split(","));casAuthenticationFilter.init();}publicvoiddestroy() {casAuthenticationFilter.destroy();}}Наш специальный фильтр оборачивает фильтр аутентификации CAS через композицию, его основная цель — просто управлять тем, какие URL-адреса должны быть аутентифицированы через CAS, в то время как мы не касались процедуры аутентификации CAS.
- В файле web.xml мы изменили определение фильтра, чтобы использовать CASCustomAuthenticationFilter вместо реализации CAS по умолчанию:
0102030405060708091011121314151617181920
<filter><filter-name>CAS Authentication Filter</filter-name><filter-class>com.programmer.gate.filters.CASCustomAuthenticationFilter</filter-class><init-param><param-name>casServerLoginUrl</param-name><param-value>https:localhost:8443/cas/login</param-value></init-param><init-param><param-name>serverName</param-name><param-value>localhost</param-value></init-param><init-param><param-name>excludeUrls</param-name><param-value>/DatabaseAuthenticatedServlet</param-value></init-param></filter><filter-mapping><filter-name>CAS Authentication Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
Вот и все, пожалуйста, оставьте свои мысли в разделе комментариев ниже.
| Опубликовано на Java Code Geeks с разрешения Хуссейна Терека, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Как исключить URL из фильтра
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |