SmartRedirectStrategy.java

  1. package cn.home1.oss.lib.security.internal.template;

  2. import static java.lang.Boolean.FALSE;
  3. import static java.lang.Boolean.TRUE;
  4. import static org.apache.commons.lang3.StringUtils.isNotBlank;

  5. import cn.home1.oss.lib.common.CodecUtils;

  6. import lombok.SneakyThrows;
  7. import lombok.extern.slf4j.Slf4j;

  8. import org.springframework.security.web.RedirectStrategy;
  9. import org.springframework.security.web.util.UrlUtils;

  10. import java.io.IOException;

  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;

  13. /**
  14.  * Created by zhanghaolun on 16/11/11.
  15.  */
  16. @Slf4j
  17. public class SmartRedirectStrategy implements RedirectStrategy {

  18.   public static final String PARAM_REDIRECT = "redirect";

  19.   private boolean contextRelative;

  20.   /**
  21.    * Redirects the response to the supplied URL.
  22.    * <p>
  23.    * If <tt>contextRelative</tt> is set, the redirect value will be the value after the
  24.    * request context path. Note that this will result in the loss of protocol
  25.    * information (HTTP or HTTPS), so will cause problems if a redirect is being
  26.    * performed to change to HTTPS, for example.
  27.    * </p>
  28.    */
  29.   @Override
  30.   public void sendRedirect( //
  31.     final HttpServletRequest request,
  32.     final HttpServletResponse response,
  33.     final String url //
  34.   ) throws IOException {
  35.     String redirectUrl = buildRedirectUrl(request, url);
  36.     redirectUrl = response.encodeRedirectURL(redirectUrl);

  37.     if (log.isDebugEnabled()) {
  38.       log.debug("Redirecting to '" + redirectUrl + "'");
  39.     }

  40.     response.sendRedirect(redirectUrl);
  41.   }

  42.   private String buildRedirectUrl( //
  43.     final HttpServletRequest request, //
  44.     final String url //
  45.   ) {
  46.     final String redirectUrl = calculateRedirectUrl(request, url);

  47.     final String requestUrl = request.getRequestURL().toString();
  48.     final String paramValue = request.getParameter(PARAM_REDIRECT);
  49.     final Boolean containsRedirectParam = containsParam(requestUrl, PARAM_REDIRECT) || isNotBlank(paramValue);
  50.     final String result;
  51.     if (containsRedirectParam) {
  52.       result = appendParam(redirectUrl, PARAM_REDIRECT, paramValue);
  53.     } else {
  54.       result = redirectUrl;
  55.     }
  56.     return result;
  57.   }

  58.   private String calculateRedirectUrl(final HttpServletRequest request, final String url) {
  59.     final String contextPath = request.getContextPath();
  60.     final String redirectUrl;
  61.     if (!UrlUtils.isAbsoluteUrl(url)) {
  62.       if (this.contextRelative) {
  63.         redirectUrl = url;
  64.       } else {
  65.         redirectUrl = contextPath + url;
  66.       }
  67.     } else {
  68.       // Full URL, including http(s)://
  69.       if (!this.contextRelative) {
  70.         redirectUrl = url;
  71.       } else {
  72.         // Calculate the relative URL from the fully qualified URL, minus the last
  73.         // occurrence of the scheme and base context.
  74.         final String withoutScheme = url.substring(url.lastIndexOf("://") + 3); // strip off scheme
  75.         final String withoutContextPath = withoutScheme.substring( //
  76.           withoutScheme.indexOf(contextPath) + contextPath.length());

  77.         if (withoutContextPath.length() > 1 && withoutContextPath.charAt(0) == '/') {
  78.           redirectUrl = url.substring(1);
  79.         } else {
  80.           redirectUrl = withoutContextPath;
  81.         }
  82.       }
  83.     }
  84.     return redirectUrl;
  85.   }

  86.   /**
  87.    * If <tt>true</tt>, causes any redirection URLs to be calculated minus the protocol
  88.    * and context path (defaults to <tt>false</tt>).
  89.    *
  90.    * @param useRelativeContext useRelativeContext
  91.    */
  92.   public void setContextRelative(final boolean useRelativeContext) {
  93.     this.contextRelative = useRelativeContext;
  94.   }

  95.   public static Boolean containsParam(final String url, final String paramName) {
  96.     Boolean containsParam = FALSE;
  97.     if (isNotBlank(url) && url.contains("?")) { // find redirect param
  98.       final String queryString = url.substring(url.indexOf('?') + 1);
  99.       final String[] params = queryString.split("&");
  100.       for (final String param : params) {
  101.         final String name = param.split("=")[0];
  102.         if (paramName.equals(name)) {
  103.           containsParam = TRUE;
  104.           break;
  105.         }
  106.       }
  107.     }
  108.     return containsParam;
  109.   }

  110.   @SneakyThrows
  111.   public static String appendParam(final String url, final String paramName, final String paramValue) {
  112.     final String param = paramName + "=" + CodecUtils.urlEncode(paramValue);
  113.     final String result;
  114.     if (url != null) {
  115.       if (url.contains("?")) {
  116.         result = url + "&" + param;
  117.       } else {
  118.         result = url + "?" + param;
  119.       }
  120.     } else {
  121.       result = null;
  122.     }
  123.     return result;
  124.   }
  125. }