Spring MVC 3 - HTTPS访问

8

如何强制页面只能通过HTTPS访问。需要通过Spring MVC 3配置文件完成此操作。

3个回答

14

Spring-security有这样的配置。在此处查看如何实现。简而言之-你可以强制通道使用https:

<http>
    <intercept-url pattern="/secure/**" access="ROLE_USER" 
        requires-channel="https"/>
    <intercept-url pattern="/**" access="ROLE_USER" 
        requires-channel="any"/>
</http>

如果您不想使用spring-security,这里是一个我写的拦截器:

@Component
public class SslInterceptor extends HandlerInterceptorAdapter {

    // no need to inject it for now..
    private PathMatcher pathMatcher = new AntPathMatcher();

    @Value("${base.url.secure}")
    private String secureRoot;

    @Resource(name="secureLocations")
    private List<String> secureLocations;

    @Value("${use.ssl}")
    private boolean useSsl;


    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        if (useSsl && !request.isSecure() && shouldForceSecure(request.getRequestURI())) {

            String redirectUrl = secureRoot + request.getRequestURI();
            if (request.getQueryString() != null) {
                redirectUrl += "?" + request.getQueryString();
            }
            // force session creation - thus it will be accessible to both the
            // secure and the insecure contexts
            request.getSession(true);
            response.sendRedirect(redirectUrl);
            return false;
        }

        return true;
    }

    private boolean shouldForceSecure(String path) {
        for (String pattern : secureLocations) {
            if (pathMatcher.match(pattern, path)) {
                return true;
            }
        }
        return false;
    }
}

谢谢Bozho。这个例子看起来很棒。您能否与我分享如何使用spring-security配置完成此操作? - Viren Pushpanayagam
正是我想要的。事实上,在发布问题之前,我确实看过这篇文章。我对Spring MVC还很陌生。我将其放入Spring配置文件中,但是我一直在遇到解析错误。我知道我要求有点多,但你能给我一个XML文件示例吗?谢谢Bozho。 - Viren Pushpanayagam
@Viren Pushpanayagam 这是另一个问题。尝试阅读整个文档,就会清楚如何配置spring-security。几周前我这样做了,它立即起作用了。 - Bozho

2

对于没有Spring安全框架的基于注释的方法,我编写了一个拦截器和一个新的注释:

/**
 * Request mapping annotation to enforce secure or insecure requests.
 * Per default the annotated mapping is enforced to be secure.
 *
 * @see org.springframework.web.bind.annotation.RequestMapping
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestProtocol {

  boolean secure() default true;
}

所以,您可以像这样简单地声明一个(这里是REST)控制器方法:
@RequestMapping(value = "/secret", method = RequestMethod.GET)
@RequestProtocol(secure = true)
@ResponseBody
public Result doSecure(@Valid Model model) {
  return doSomething(model));
}

为了启用映射,请使用拦截器在错误的协议上进行重定向。您也可以通过只发送FORBIDDEN响应来进行更简单的处理。
/**
 * Interceptor to send a redirect on security enforced mappings with wrong type of request.
 *
 * @see RequestProtocol
 */
class RequestProtocolInterceptor extends HandlerInterceptorAdapter {

  private static final int PORT_DIFF = 443 - 80;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
    Boolean secure = checkSecure(handler);
    if (secure != null && request.isSecure() != secure) {
      response.sendRedirect(switchSecure(secure, request.getRequestURL()));
      return false;
    }
    return true;
  }

  private Boolean checkSecure(Object handler) {
    if (handler instanceof HandlerMethod) {
      HandlerMethod method = (HandlerMethod)handler;
      RequestProtocol annotation = method.getMethodAnnotation(RequestProtocol.class);
      if (annotation == null) {
        annotation = AnnotationUtils.findAnnotation(method.getBeanType(), RequestProtocol.class);
      }
      return annotation == null ? null : annotation.secure();
    }
    return null;
  }

  private String switchSecure(boolean secure, StringBuffer url) {
    int endSchema = url.indexOf("://");
    url.replace(0, endSchema, secure ? "https" : "http");
    int startPort = url.indexOf(":", endSchema + 3);
    if (startPort != -1) {
      int endPort = url.indexOf("/", startPort);
      int port = Integer.parseInt(url.substring(startPort + 1, endPort));
      port += secure ? PORT_DIFF : -PORT_DIFF;
      url.replace(startPort + 1, endPort, String.valueOf(port));
    }
    return url.toString();
  }
}

为了在基于纯注释的Spring配置中启用拦截器,请使用WebMvcConfigurerAdapter:
@Configuration
@EnableWebMvc
public class MyConfiguration extends WebMvcConfigurerAdapter {

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new RequestProtocolInterceptor());
  }
}

1

您可以在Tomcat配置中完成此操作。

尝试在server.xml中的HTTP连接器中添加redirectPort =""。

希望能对您有所帮助。

更新:

本文将为您解释如何处理SSL,并提供了很多示例。

http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html


同意,但每个应用服务器都有这样的选项,甚至包括IIS :)。我只是提出了应该做什么的想法。 - danny.lesnik
请您能够提供一个例子。 - Viren Pushpanayagam
谢谢@Danny,但是我想知道如何在Spring MVC 3中实现它。 - Viren Pushpanayagam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接