Spring Security3源码分析(19)-SSL支持

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

Sping Security3对于SSL的支持仅仅表现在对需要拦截的url(标签intercept-url)设置requires-channel=https属性。

如果一个url设置了requires-channel为https,那么该url在http的访问会直接重定向到https的通道中去。后面再具体分析。

首先需要在应用中配置SSL的支持,具体配置方法可参考

http://lengyun3566.iteye.com/blog/1141347

Sping Security3支持SSL分别表现下面几个类

类名称 用途描述
类名称 用途描述
ChannelProcessingFilter 通道处理过滤器。只要intercept-url标签中包含requires-channel属性,该过滤器就被创建
ChannelDecisionManagerImpl 通道决策管理器。该管理器包含两个ChannelProcessor实例用于处理安全、不安全两种Channel方式
SecureChannelProcessor 安全通道处理器
InsecureChannelProcessor 不安全通道处理器
AbstractRetryEntryPoint 抽象的通道重操作入口点,是entrypoint的父类
RetryWithHttpEntryPoint 如果当前以安全通道访问不安全通道,也可以通过http的入口点重定向到不安全通道中
RetryWithHttpsEntryPoint 如果当前以不安全通道访问安全通道,就要通过https的入口点重定向到安全通道中
PortMapperImpl 端口映射处理。主要是针对非默认端口(80、8080、443、8443)的情况

看ChannelProcessingFilter过滤器的作用

ChannelProcessingFilter首先检查当前请求的url是否已配置了requires-channel属性,如果没配置,不处理。如果配置了,就把决策权交给ChannelDecisionManagerImpl处理。

ChannelProcessingFilter对应类路径:org.springframework.security.web.access.channel.ChannelProcessingFilter

具体源码如下

Java代码

  1. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
  2. throws IOException, ServletException {
  3. HttpServletRequest request = (HttpServletRequest) req;
  4. HttpServletResponse response = (HttpServletResponse) res;
  5. FilterInvocation fi = new FilterInvocation(request, response, chain);
  6. //获取url的权限配置信息
  7. Collection attr = this.securityMetadataSource.getAttributes(fi);
  8. if (attr != null) {
  9. if (logger.isDebugEnabled()) {
  10. logger.debug(“Request: “ + fi.toString() + “; ConfigAttributes: “ + attr);
  11. }
  12. //把决策权交给channelDecisionManager处理
  13. channelDecisionManager.decide(fi, attr);
  14. if (fi.getResponse().isCommitted()) {
  15. return;
  16. }
  17. }
  18. chain.doFilter(request, response);
  19. }

接着看ChannelDecisionManagerImpl的作用

ChannelDecisionManagerImpl根据requires-channel的值做相应处理,requires-channel值有以下三种

any:任何通道都支持。决策管理器不做处理

https:只支持安全通道。决策管理器把决策任务交给ChannelProcessor列表循环处理

http:只支持http。决策管理器把决策任务交给ChannelProcessor列表循环处理

ChannelDecisionManagerImpl的源码为:

Java代码

  1. public void decide(FilterInvocation invocation, Collection config) throws IOException, ServletException {
  2. Iterator attrs = config.iterator();
  3. //判断是否为any值
  4. while (attrs.hasNext()) {
  5. ConfigAttribute attribute = attrs.next();
  6. if (ANY_CHANNEL.equals(attribute.getAttribute())) {
  7. return;
  8. }
  9. }
  10. //循环ChannelProcessor列表执行decide
  11. for (ChannelProcessor processor : channelProcessors) {
  12. processor.decide(invocation, config);
  13. if (invocation.getResponse().isCommitted()) {
  14. break;
  15. }
  16. }
  17. }

继续看ChannelProcessor 的作用

实际上在构造ChannelDecisionManager的bean时,已经注入了两个ChannelProcessor ,分别是SecureChannelProcessor、InsecureChannelProcessor

先看SecureChannelProcessor(负责处理安全通道)执行过程

Java代码

  1. public void decide(FilterInvocation invocation, Collection config) throws IOException, ServletException {
  2. Assert.isTrue((invocation != null) && (config != null), “Nulls cannot be provided”);
  3. for (ConfigAttribute attribute : config) {
  4. if (supports(attribute)) {
  5. if (!invocation.getHttpRequest().isSecure()) {
  6. entryPoint.commence(invocation.getRequest(), invocation.getResponse());
  7. }
  8. }
  9. }
  10. }

根据当前的请求是否安全,进行相应的处理。实际工作的是抽象的父类AbstractRetryEntryPoint的commence完成

AbstractRetryEntryPoint的commence方法源码:

Java代码

  1. public void commence(HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException {
  2. String pathInfo = request.getPathInfo();
  3. String queryString = request.getQueryString();
  4. String contextPath = request.getContextPath();
  5. String destination = request.getServletPath() + ((pathInfo == null) ? “” : pathInfo)
  6. + ((queryString == null) ? “” : (“?” + queryString));
  7. String redirectUrl = contextPath;
  8. //获取当前请求所在端口
  9. Integer currentPort = new Integer(portResolver.getServerPort(request));
  10. //根据当前端口获得映射的端口(需要配置port-mappings标签),如果是http的访问,则获取映射的https端口,如果是https的访问,则获取相应的http端口
  11. Integer redirectPort = getMappedPort(currentPort);
  12. //如果获取到匹配端口,则根据当前请求构造重定向请求的url
  13. if (redirectPort != null) {
  14. boolean includePort = redirectPort.intValue() != standardPort;
  15. redirectUrl = scheme + request.getServerName() + ((includePort) ? (“:” + redirectPort) : “”) + contextPath
  16. + destination;
  17. }
  18. if (logger.isDebugEnabled()) {
  19. logger.debug(“Redirecting to: “ + redirectUrl);
  20. }
  21. //执行重定向操作
  22. res.sendRedirect(res.encodeRedirectURL(redirectUrl));
  23. }

通过以上分析,应该很清楚的知道:

如果以http的方式登录到应用中,再访问配置了requires-channel=https的url时,就会重定向到https的通道去,以SSL方式访问。

如果以https的方式登录到应用中,再访问配置了requires-channel=http的url时,就会重定向到http的通道去,以不安全的方式访问。


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Security3源码分析(19)-SSL支持

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏