Spring mvc 3 - HTTPS access
How can I force a page to be accessed via HTTPS only. Need to do this v开发者_如何学编程ia Spring MVC 3 configuration file.
Spring-security has such a configuration. see here for how to do it. In short - you force the channel to use https:
<http>
<intercept-url pattern="/secure/**" access="ROLE_USER"
requires-channel="https"/>
<intercept-url pattern="/**" access="ROLE_USER"
requires-channel="any"/>
</http>
If you don't want to use spring-security, here's an interceptor that I wrote:
@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;
}
}
For an annotation based approach without spring security I wrote an interceptor and a new annotation:
/**
* 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;
}
So you can simply declare a (here for REST) controller method like this:
@RequestMapping(value = "/secret", method = RequestMethod.GET)
@RequestProtocol(secure = true)
@ResponseBody
public Result doSecure(@Valid Model model) {
return doSomething(model));
}
To enable the mapping use an interceptor redirecting on the wrong protocol. You could also do a more simple handling by just sending a FORBIDDEN response.
/**
* 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();
}
}
To enable the interceptor on a pure annotation based Spring config, use the WebMvcConfigurerAdapter:
@Configuration
@EnableWebMvc
public class MyConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestProtocolInterceptor());
}
}
You can do it in your Tomcat config.
try adding redirectPort="" in server.xml to the HTTP connector.
Hope it helps.
Update:
This article will explain you how to deal with SSL and has a lot of an examples.
http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html
精彩评论