繁体   English   中英

Spring Security - 使用 java 配置的自定义预授权过滤器

[英]Spring Security - Custom Pre Auth filter using java config

我正在尝试配置一个简单的自定义身份验证过滤器,用于检查 Web 应用程序除“/登录”页面之外的每个页面上的令牌。 现在,过滤器已启动并运行,但无论我更改什么设置,都会在每个页面上调用过滤器,包括我已设置为 permitAll() 的“/login”。

当我访问 localhost:8080/login 时,我希望它不会根据我下面的配置调用此过滤器,而是在过滤器中抛出异常,因为没有找到会话。

我的问题是如何将过滤器限制为除“/登录”页面之外的所有页面?

这是我的配置:

@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();
}

}

这是过滤器:

    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;
    }

下面的代码过滤特定端点的未授权/会话过期请求。 Bean 应与端点 URL 一起配置,以便 Auth 过滤器适用于该端点。 现在通过这样做,您可以将过滤器应用程序限制为仅用于您想要的端点。

@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;
    }

授权过滤器

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);
  }
}```

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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