使用 Spring Security 定义 HTTP 路由以仅服务“内部”请求

Posted

技术标签:

【中文标题】使用 Spring Security 定义 HTTP 路由以仅服务“内部”请求【英文标题】:Define HTTP routes to serve only "internal" requests with Spring Security 【发布时间】:2014-06-16 22:37:12 【问题描述】:

我的问题可能看起来有点奇怪,但我想更好地了解 Spring Security 的工作原理。

我有一个场景如下...

通过使用 Spring SecuritySpring SAML,我定义了一个入口点、一些模式和过滤器,以便正确管理 http 请求。

<!-- Secured pages -->
<security:http entry-point-ref="samlEntryPoint"
    use-expressions="true">
    <security:intercept-url pattern="/" access="permitAll" />
    <security:intercept-url pattern="/saml/**" access="permitAll" />
    <security:intercept-url pattern="/metadata" access="permitAll" />
    <security:intercept-url pattern="/metadata/**" access="permitAll" />
    <security:intercept-url pattern="/info" access="isAuthenticated()" />
    <security:intercept-url pattern="/signup/sso" access="permitAll" />
    <security:custom-filter before="FIRST"
        ref="metadataGeneratorFilter" />
    <security:custom-filter after="BASIC_AUTH_FILTER"
        ref="samlFilter" />
</security:http>

<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
    <security:filter-chain-map request-matcher="ant">
        <security:filter-chain pattern="/saml/login/**"
            filters="samlEntryPoint" />
        <security:filter-chain pattern="/saml/logout/**"
            filters="samlLogoutFilter" />
        <security:filter-chain pattern="/saml/metadata/**"
            filters="metadataDisplayFilter" />
        <security:filter-chain pattern="/saml/SSO/**"
            filters="samlWebSSOProcessingFilter" />
        <security:filter-chain pattern="/saml/SSOHoK/**"
            filters="samlWebSSOHoKProcessingFilter" />
        <security:filter-chain pattern="/saml/SingleLogout/**"
            filters="samlLogoutProcessingFilter" />
        <security:filter-chain pattern="/saml/discovery/**"
            filters="samlIDPDiscovery" />
    </security:filter-chain-map>
</bean>

然后,我还定义了一个 IdP 发现服务

<!-- IDP Discovery Service -->
<bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
    <property name="idpSelectionPath" value="/sso/idpSelection" />
</bean>

最后,我实现了一个web-controller来为/sso/idpSelection提供http请求:

@Controller
@RequestMapping("/sso")
public class SSOController 
    // Logger
    private static final Logger LOG = LoggerFactory.getLogger(SSOController.class);

    @Autowired
    private ServletContext servletContext;

    @RequestMapping(value = "/idpSelection", method = RequestMethod.GET)
    public String idpSelection(HttpServletRequest request, Model model)            
        WebApplicationContext context = WebApplicationContextUtils
                .getWebApplicationContext(request.getServletContext());
        MetadataManager metadataManager = context.getBean("metadata", MetadataManager.class);
        Set<String> idps = metadataManager.getIDPEntityNames();
        for (String idp : idps)
            LOG.info("Configured Identity Provider for SSO: " + idp);
        model.addAttribute("idp", idps);
        return "sso/idpselection";
    

当匿名用户尝试访问受保护的页面时,过滤器会将他的请求重定向到 /saml/discovery,因此 IdP 发现服务会为 /sso/idpSelection 调用控制器。

很明显,路由 /sso/idpSelection 应仅由 IdP 发现服务使用,作为内部资源。

有没有办法拒绝直接访问请求(例如通过浏览器)但同时允许内部进程的路由?

【问题讨论】:

【参考方案1】:

SAMLDiscovery 在将用户发送到 /sso/idpSelection 时进行转发。这意味着您可以通过以下方式以编程方式禁止用户直接访问页面:

@RequestMapping(value = "/idpSelection", method = RequestMethod.GET)
public String idpSelection(HttpServletRequest request, Model model)   
   if (request.getAttribute("javax.servlet.forward.request_uri") == null) 
       // Deny access
   
   ...

属性“javax.servlet.forward.request_uri”在调用 requestDispatcher 的 forward 方法时由容器自动设置,因此不会出现在直接请求中。该功能从 Servlet 2.4 开始可用。

【讨论】:

以上是关于使用 Spring Security 定义 HTTP 路由以仅服务“内部”请求的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security - 更改 RedirectStrategy 的所有实例

如何使用 Spring Security 仅接受 https 流量并拒绝所有 http 流量?

具有角色的经过身份验证的用户的 Spring Security Java 配置

如何在我的 Spring 4.0 RestFul Web 服务上实现 Spring Security?

angularjs,rest api,spring security,休眠任何应用程序

负载均衡器后面带有 Spring Security 的 Spring Boot:将 HTTP 重定向到 HTTPS