que filtro ejemplo delegatingfilterproxy java spring spring-mvc

java - ejemplo - ¿Cómo crear mi propio filtro con Spring MVC?



spring security filter chain (7)

A continuación se muestra el filtro para realizar la lógica que ha mencionado.

@WebFilter("/*") public class AuthTokenFilter implements Filter { @Override public void destroy() { // ... } @Override public void init(FilterConfig filterConfig) throws ServletException { // } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String xHeader = ((HttpServletRequest)request).getHeader("X-Auth-Token"); if(getPermission(xHeader)) { chain.doFilter(request, response); } else { request.getRequestDispatcher("401.html").forward(request, response); } } }

Y lo hiciste bien, la configuración de primavera debería estar siguiendo.

public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Filter[] getServletFilters() { return new Filter[]{new AuthTokenFilter()}; } }

Uso Spring MVC (4.0.1) como backend para servicios de descanso y angularjs como frontend.

cada solicitud a mi servidor backend tiene un encabezado http con un ID de sesión

Puedo leer este encabezado en el servidor de mi servidor con el siguiente código:

@Autowired protected HttpServletRequest request; String xHeader=request.getHeader("X-Auth-Token"); //returns the sessionID from the header

Ahora llamo a este método getPermission(xHeader) que devuelve solo verdadero o falso. Si el usuario existe en mi base de datos, devuelve true o false.

Ahora quiero crear un filtro con este comportamiento, que verifique todas las solicitudes si el usuario tiene permiso para acceder a mis controladores. ¡Pero si el método devuelve falso, debería devolver un error 401 y no alcanzar mi controlador!

¿Cómo puedo hacer esto y crear mi propio filtro? Solo uso Java Config y no XML.

Creo que debo agregar el filtro aquí:

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Filter[] getServletFilters() { MyOwnFilter=new MyOwnFilter(); return new Filter[] {MyOwnFilter}; } }


Alternativa a los filtros, puede utilizar HandlerInterceptor .

public class SessionManager implements HandlerInterceptor{ // This method is called before the controller @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String xHeader = request.getHeader("X-Auth-Token"); boolean permission = getPermission(xHeader); if(permission) { return true; } else { response.setStatus(HttpStatus.UNAUTHORIZED.value()); return false; // Above code will send a 401 with no response body. // If you need a 401 view, do a redirect instead of // returning false. // response.sendRedirect("/401"); // assuming you have a handler mapping for 401 } return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }

Y luego agregue este interceptor a su configuración webmvc.

@EnableWebMvc @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Bean SessionManager getSessionManager() { return new SessionManager(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getSessionManager()) .addPathPatterns("/**") .excludePathPatterns("/resources/**", "/login"); // assuming you put your serve your static files with /resources/ mapping // and the pre login page is served with /login mapping } }


Puede crear y configurar su propio filtro siguiendo estos pasos.

1) Cree su clase implementando la interfaz de filtro y anule sus métodos.

public class MyFilter implements javax.servlet.Filter{ public void destroy(){} public void doFilter(Request, Response, FilterChain){//do what you want to filter } ........ }

2) Ahora configura tu filtro en web.xml

<filter> <filter-name>myFilter</filter-name> <filter-class>MyFilter</filter-class> </filter>

3) Ahora proporcione la asignación de URL del filtro.

<filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>*</url-pattern> </filter-mapping>

4) Ahora reinicie su servidor y verifique que todas las solicitudes web lleguen primero a MyFilter y luego al controlador respectivo.

Esperemos que sea la respuesta requerida.


Spring puede usar filtros, pero recomiendan que uses su versión de filtros, conocida como un interceptor

http://viralpatel.net/blogs/spring-mvc-interceptor-example/

Hay una rápida descripción de cómo funcionan. Son casi idénticos a los filtros, pero están diseñados para funcionar dentro del ciclo de vida de Spring MVC.


Su enfoque se ve correcto.

Una vez usé algo similar a seguir (eliminé la mayoría de las líneas y lo mantuve simple).

public class MvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ERROR); FilterRegistration.Dynamic monitoringFilter = servletContext.addFilter("monitoringFilter", MonitoringFilter.class); monitoringFilter.addMappingForUrlPatterns(dispatcherTypes, false, "/api/admin/*"); } @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { WebMvcConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }

También necesitas un filtro personalizado que se ve a continuación.

public class CustomXHeaderFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String xHeader = request.getHeader("X-Auth-Token"); if(YOUR xHeader validation fails){ //Redirect to a view //OR something similar return; }else{ //If the xHeader is OK, go through the chain as a proper request chain.doFilter(request, response); } } @Override public void destroy() { } @Override public void init(FilterConfig arg0) throws ServletException { } }

Espero que esto ayude.

Además, puede usar FilterRegistrationBean si FilterRegistrationBean Spring Boot. Hace lo mismo (creo que sí) que FilterRegistration.Dynamic hace.


Supongo que está intentando implementar algún tipo de seguridad OAuth que se basa en el token jwt.

Hoy en día hay varias formas de hacerlo, pero aquí está mi favorita:

Así es como se ve el filtro:

import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.web.filter.GenericFilterBean; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureException; public class JwtFilter extends GenericFilterBean { @Override public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) req; final String authHeader = request.getHeader("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { throw new ServletException("Missing or invalid Authorization header."); } final String token = authHeader.substring(7); // The part after "Bearer " try { final Claims claims = Jwts.parser().setSigningKey("secretkey") .parseClaimsJws(token).getBody(); request.setAttribute("claims", claims); } catch (final SignatureException e) { throw new ServletException("Invalid token."); } chain.doFilter(req, res); } }

Bastante simple es el controlador de usuario también donde puede encontrar el método de inicio de sesión:

import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @RestController @RequestMapping("/user") public class UserController { private final Map<String, List<String>> userDb = new HashMap<>(); public UserController() { userDb.put("tom", Arrays.asList("user")); userDb.put("sally", Arrays.asList("user", "admin")); } @RequestMapping(value = "login", method = RequestMethod.POST) public LoginResponse login(@RequestBody final UserLogin login) throws ServletException { if (login.name == null || !userDb.containsKey(login.name)) { throw new ServletException("Invalid login"); } return new LoginResponse(Jwts.builder().setSubject(login.name) .claim("roles", userDb.get(login.name)).setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, "secretkey").compact()); } @SuppressWarnings("unused") private static class UserLogin { public String name; public String password; } @SuppressWarnings("unused") private static class LoginResponse { public String token; public LoginResponse(final String token) { this.token = token; } } }

Por supuesto tenemos Main donde puedes ver el bean de filtro:

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @EnableAutoConfiguration @ComponentScan @Configuration public class WebApplication { @Bean public FilterRegistrationBean jwtFilter() { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new JwtFilter()); registrationBean.addUrlPatterns("/api/*"); return registrationBean; } public static void main(final String[] args) throws Exception { SpringApplication.run(WebApplication.class, args); } }

Por último, pero no menos importante, hay un controlador de ejemplo:

import io.jsonwebtoken.Claims; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class ApiController { @SuppressWarnings("unchecked") @RequestMapping(value = "role/{role}", method = RequestMethod.GET) public Boolean login(@PathVariable final String role, final HttpServletRequest request) throws ServletException { final Claims claims = (Claims) request.getAttribute("claims"); return ((List<String>) claims.get("roles")).contains(role); } }

Here hay un enlace a GitHub. Gracias a nielsutrecht por el gran trabajo que he usado este proyecto como base y funciona perfectamente.


También puede implementarlo utilizando un aspecto con un punto de corte que apunte a una anotación determinada. He escrito una biblioteca que le permite utilizar anotaciones que realizan comprobaciones de autorización basadas en un token JWT.

Puede encontrar el proyecto con toda la documentación en: https://github.com/nille85/jwt-aspect . He utilizado este enfoque varias veces para asegurar un Backend REST que consume una aplicación de una sola página.

También he documentado en mi blog cómo puede usarlo en una aplicación Spring MVC: http://www.nille.be/security/creating-authorization-server-using-jwts/

Lo siguiente es un extracto del proyecto de ejemplo en https://github.com/nille85/auth-server

El siguiente ejemplo contiene un método protegido getClient. La anotación @Authorize que utiliza el aspecto comprueba si el valor de "aud jwt claim" coincide con el parámetro clientId que se anota con @ClaimValue . Si coincide, se puede introducir el método. De lo contrario se lanza una excepción.

@RestController @RequestMapping(path = "/clients") public class ClientController { private final ClientService clientService; @Autowired public ClientController(final ClientService clientService) { this.clientService = clientService; } @Authorize("hasClaim(''aud'',''#clientid'')") @RequestMapping(value = "/{clientid}", method = RequestMethod.GET, produces = "application/json") @ResponseStatus(value = HttpStatus.OK) public @ResponseBody Client getClient(@PathVariable(value = "clientid") @ClaimValue(value = "clientid") final String clientId) { return clientService.getClient(clientId); } @RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json") @ResponseStatus(value = HttpStatus.OK) public @ResponseBody List<Client> getClients() { return clientService.getClients(); } @RequestMapping(path = "", method = RequestMethod.POST, produces = "application/json") @ResponseStatus(value = HttpStatus.OK) public @ResponseBody Client registerClient(@RequestBody RegisterClientCommand command) { return clientService.register(command); } }

El Aspecto en sí puede configurarse como:

@Bean public JWTAspect jwtAspect() { JWTAspect aspect = new JWTAspect(payloadService()); return aspect; }

El PayloadService que se necesita se puede implementar, por ejemplo, como:

public class PayloadRequestService implements PayloadService { private final JWTVerifier verifier; public PayloadRequestService(final JWTVerifier verifier){ this.verifier = verifier; } @Override public Payload verify() { ServletRequestAttributes t = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = t.getRequest(); final String jwtValue = request.getHeader("X-AUTH"); JWT jwt = new JWT(jwtValue); Payload payload =verifier.verify(jwt); return payload; } }