简体   繁体   中英

Spring Security - Custom Pre Auth filter using java config

I am trying to configure a simple custom authentication filter that checks for a token on every page of the web app except the '/login' page. Right now, the filter is up and running, but no matter what settings I change, the filter is being called on every page, including '/login' which I have set to permitAll().

When I access localhost:8080/login, I expect it to not call this filter based on my configuration below, but instead it throws an exception in the filter because no session is found.

My question is how do I limit the filter to all pages except the '/login' page?

Here is my config:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

private UserDetailsService userDetailsService;
private PreAuthenticatedAuthenticationProvider preAuthenticatedProvider;

public SecurityConfig() {
    super();

    userDetailsService = new UserDetailsServiceImpl();
    UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper = 
            new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(userDetailsService);

    preAuthenticatedProvider = new PreAuthenticatedAuthenticationProvider();
    preAuthenticatedProvider.setPreAuthenticatedUserDetailsService(wrapper);
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(preAuthenticatedProvider);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    OpenTokenRequestAuthenticationFilter filter = new OpenTokenRequestAuthenticationFilter();
    filter.setAuthenticationManager(authenticationManager());


    http
        .addFilter(filter)
        .authorizeRequests()
            .antMatchers("/login").permitAll();
}

}

And here is the filter:

    public class OpenTokenRequestAuthenticationFilter extends
        AbstractPreAuthenticatedProcessingFilter {

    /**
     * logger for the class
     */
    private static final Logger logger = LoggerFactory.getLogger(OpenTokenRequestAuthenticationFilter.class);

    @Autowired
    private ExceptionMappingAuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    private IOpenTokenReader openTokenReader;

    private String logoutURL;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)request;
        HttpServletResponse httpServletResponse = (HttpServletResponse)response;
        super.doFilter(httpServletRequest, httpServletResponse, chain);
        HttpSession session = httpServletRequest.getSession(false);
        if(session != null && session.getAttribute("ssoToken") != null)
        {
            SsoToken ssoToken = (SsoToken)session.getAttribute("ssoToken");
            httpServletResponse.addHeader("agentName", ssoToken.getName());
            httpServletResponse.addHeader("agentID", ""+ssoToken.getLoginId());
        }
    }

    /**
     * 
     */
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        String principal = null;
        HttpSession session = null;

        try {
            session = request.getSession(false);
            String tokenName = openTokenReader.getTokenName();

            if (tokenName != null && request.getParameter(tokenName.trim()) != null && !request.getParameter(tokenName.trim()).isEmpty()) {
                logger.info("Token found in request. Token Name:  "+ tokenName);
                SsoToken ssoToken = null;
                if (session != null) {
                    session.invalidate();
                    logger.info("Invalidated old session and creating a new session since request found with new token.");
                }
                session = request.getSession(true);//create new session
                logger.info("New session created: "+session.getId());

                Agent agent = openTokenReader.getAgent();
                Map result = agent.readToken(request);
                if (result != null) {
                    principal = (String) result.get("subject");
                    ssoToken = new SsoToken();
                    ssoToken.setLogoutURL(getLogoutURL());
//                  ssoToken.setName((String) result.get("lastName") +", "+(String) result.get("firstName"));
                    ssoToken.setName((String) result.get("firstName"));
                    ssoToken.setAffiliate((result.get("isAffiliate") != null && !((String)result.get("isAffiliate")).trim().equals("false")) ? true : false);
                    if(ssoToken.isAffiliate())
                        ssoToken.setLoginId((String) result.get("affiliateId"));
                    else
                        ssoToken.setLoginId((String) result.get("subject"));
                }
                session.setAttribute("ssoToken", ssoToken);
                boolean isInValidToken = hasInvalidTokenData(ssoToken);
                if (isInValidToken) {
                    throw new PreAuthenticatedCredentialsNotFoundException("Invalid Token found in request.");
                } else {
                    session.setAttribute("hasValidToken", true);
                }
            }

        } catch (Exception e) {
            logger.error("Exception while reading token " + e);
        }
        if(session == null )
            throw new PreAuthenticatedCredentialsNotFoundException("No session found.");
        if(session != null && session.getAttribute("hasValidToken") == null)
            throw new PreAuthenticatedCredentialsNotFoundException("No attribute 'hasValidToken' found in session.");
        if(session != null && session.getAttribute("hasValidToken") != null && !(Boolean) session.getAttribute("hasValidToken"))
            throw new PreAuthenticatedCredentialsNotFoundException("value of  attribute 'hasValidToken' is false in session.");

        /*if (session == null || session.getAttribute("hasValidToken") == null || !((Boolean) session.getAttribute("hasValidToken"))){
            throw new PreAuthenticatedCredentialsNotFoundException("Token not found in request.");
        }*/
        if(session != null && session.getAttribute("ssoToken") != null)
        {
            SsoToken ssoToken = (SsoToken)session.getAttribute("ssoToken");
            principal = ssoToken.getLoginId();
        }

        return principal;
    }
    public boolean hasInvalidTokenData(SsoToken token) {
        boolean hasInvalidTokenData = false;
        if (token == null) {
            hasInvalidTokenData = true;
        } else {
            if (StringUtils.isBlank(token.getLoginId())) {
                logger.debug("Login ID was blank.");
                hasInvalidTokenData = true;
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Exiting: hasInvalidTokenData(SsoToken)");
            logger.debug("hasInvalidTokenData=|" + hasInvalidTokenData + "|");
        }
        return hasInvalidTokenData;
    }
    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        return "";
    }

    /**
     * @return the logoutURL
     */
    public String getLogoutURL() {
        return logoutURL;
    }

    /**
     * @param logoutURL the logoutURL to set
     */
    public void setLogoutURL(String logoutURL) {
        this.logoutURL = logoutURL;
    }

    public void setAuthenticationFailureHandler(ExceptionMappingAuthenticationFailureHandler authenticationFailureHandler){
        this.authenticationFailureHandler = authenticationFailureHandler;
    }

    public ExceptionMappingAuthenticationFailureHandler getAuthenticationFailureHandler(){
        return authenticationFailureHandler;
    }

The below code Filters the unauthorized/Session expired requests for a particular endpoint. The Bean should be configured along with the endpoint URL so the Auth filter will be applicable for that endpoint. Now by doing so you can restric the filter application for only the endpoints which you want.

@Bean
public FilterRegistrationBean<AuthFilter> filterRegistrationBean() {
        FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();
        AuthFilter authFilter = new AuthFilter();
        registrationBean.setFilter(authFilter);
        // Include the URL patterns for which the Auth filter should be applicable 
        registrationBean.addUrlPatterns("/api/protectedendpoint/*");
        return registrationBean;
    }

Auth Filter

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import java.io.IOException;


public class AuthFilter extends GenericFilterBean {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    String authHeader = httpRequest.getHeader("Authorization");
    if (authHeader != null) {
      String[] authHeaderArr = authHeader.split("Bearer ");
      if (authHeaderArr.length > 1 && authHeaderArr[1] != null) {
        String token = authHeaderArr[1];

        try {
          Claims claims = Jwts.parser().setSigningKey(YOUR_JWT_SECRET_KEY).parseClaimsJws(token).getBody();
          httpRequest.setAttribute("email", claims.get("email").toString());
        } catch (Exception e) {
          httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "invalid/expired token");
          return;
        }
      } else {
        httpResponse.sendError(HttpStatus.FORBIDDEN.value(), "Authorization token must be Bearer [token]");
        return;
      }
    } else {
      httpResponse.sendError(HttpStatus.UNAUTHORIZED.value(), "Authorization token must be provided");
      return;
    }
    chain.doFilter(httpRequest, httpResponse);
  }
}```

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM