带有 Spring Security 的 AngularJS Web 应用程序

Posted

技术标签:

【中文标题】带有 Spring Security 的 AngularJS Web 应用程序【英文标题】:AngularJS Web Application with Spring Security 【发布时间】:2014-07-18 03:30:56 【问题描述】:

我正在努力在 AngularJS 应用程序中实现 Spring Security。我对这两种技术都比较陌生,我发现了几个非常有用的网站,其中包含有关如何实现 AngularJS 和 Spring Security 的教程和示例。

我目前的问题在于限制某些用户的 URL 路径。 IT 听起来像是一个简单的问题,但我被文档淹没了自己,试图找出以前必须解决的问题。

在 AngularJS 中,当导航到不同的 URL 时,URL 中有一个井号标记,这似乎会导致 Spring 出现问题。没有抛出错误,但资源不受限制。我的代码如下:

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/paperwebapp-servlet.xml
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>webapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>*</param-value>
        </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>webapp</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Apply Spring Security Filter to all Requests -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

app-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

<context:property-placeholder location="file:$catalina_home/conf/application.properties" />

<mvc:view-controller path="/" view-name="/resources/index.html"/>
<mvc:resources mapping="/resources/**" location="/resources/" />

<import resource="spring-security.xml" />

</beans>

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:sec="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security.xsd">

<context:property-placeholder location="file:$catalina_home/conf/application.properties" />

<sec:http auto-config='true'>
    <sec:intercept-url pattern="/access/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <sec:intercept-url pattern="/*" access="ROLE_USER" />
    <sec:intercept-url pattern="/#/inventory" access="ROLE_ADMIN" />

    <sec:form-login login-page="/access/login.jsp" default-target-url="/#/splash"
        always-use-default-target="true" />
</sec:http>

<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider>
        <sec:user-service>
            <sec:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
            <sec:user name="user" password="user" authorities="ROLE_USER" />
        </sec:user-service>
    </sec:authentication-provider>
</sec:authentication-manager>
</beans>

部署应用程序后,我可以访问 URL (localhost:8080/app) 并按预期显示登录页面。一旦我通过身份验证,我也会按预期被带到启动屏幕(/#/splash)。但是,如果我使用“用户”凭据登录,我应该受到 /inventory 路径的限制。无论我尝试什么(/#/inventory、/inventory、#/inventory 等),我都无法限制资源。我已经在直接从应用程序目录访问 HTML 页面的应用程序上测试了此配置,它似乎工作正常,因此我确信它与 AngularJS 控制器路由请求并使用该哈希标记有关。

我在研究中发现的另一个兴趣点是,因为我们使用来自多个来源的模板来编译每个页面,所以我们不能使用 $locationProvider 来设置 HTML5 模式而不破坏应用程序。

如果有人对此问题有任何见解,将不胜感激。我确信这已经在某个地方,但对于我的生活,我找不到任何东西。谢谢!

【问题讨论】:

【参考方案1】:

您似乎将 Angular 的客户端 URL 处理(基于哈希,如“/#/splash”)与 Spring MVC(以及 Spring Security)的服务器端 URL 处理混淆了。

请记住,Spring Security 在服务器端保护对 URL 的访问,而 Angular 是一个单页的客户端库。

当你第一次访问你的 Angular 页面时,你是从服务器获取的,Spring Security 可以根据登录来限制访问。

如果您仍然在客户端的单页 Angular 环境中,并通过 Angular 导航到 URL 中带有哈希的“页面”(请参阅​​AngularJS $location guide about hashbang URLs),则您没有发出服务器请求。您正在请求 Angular 呈现不同的模板或状态。这是客户端行为,因此不涉及 Spring Security。当您访问模板 HTML 文件(Spring 可能会在未经身份验证的情况下静态返回)或您已设置 REST api 以从您的服务器获取数据(通常返回 JSON 格式的数据供您的应用程序使用)时,您会发出服务器请求。

我相信,要完成这项工作,您的受保护资源(“/inventory”)的数据不必包含在主应用程序中,需要单独的服务器端资源。这可能包括页面和/或数据的 HTML 模板。您的 AngularJS 应用程序应该能够识别此资源不可用并向用户显示一些内容以传达缺乏授权。

【讨论】:

这是一个有趣的观点。我刚刚和这个应用程序的 UI 开发人员谈过,他说了一些非常相似的话,我应该专注于保护 Web 服务 API 而不是 Angular 应用程序“页面”本身。我没有意识到整个 Angular 应用程序是一个页面。这很可能需要我从不同的角度来解决这个问题。谢谢你的建议!

以上是关于带有 Spring Security 的 AngularJS Web 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

带有 OpenIDAuthenticationFilter 问题的 Spring Security

带有 spring-boot 和 spring-security 的 JWT

带有 Spring Security 的 Spring REST 不接受凭据

带有 LDAP 注销的 Spring Security 无法删除会话

如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?

我们如何使用带有 Spring 5.0 的最新 spring-security-oauth2 jar 来实现授权服务器?