【问题标题】:Spring Security Token Authentication - RESTful JSON ServiceSpring Security Token Authentication - RESTful JSON 服务
【发布时间】:2014-07-31 18:49:35
【问题描述】:

我希望将 Spring Security 用于 Spring MVC 应用程序,该应用程序严格来说是 JSON Web 服务。我做了一些研究并阅读了几篇文章,但还没有真正找到任何完整的东西。我希望应用程序完全无状态并使用基于令牌的身份验证。我不希望 Spring MVC 应用程序有任何表单,或者使用表单进行身份验证。它应该严格接受 JSON 格式的请求和数据,并返回 JSON 响应。

会有一个 Angular JS 客户端应用程序需要发送用户名和密码,并从应用程序获取令牌以用于顺序请求。在某些时候,可能会有 Android 客户端也访问此 Web 服务。

我假设 Spring Security 在内部有自己的方式将令牌映射到用户会话,这意味着它知道令牌 XXXXXXXXXXXX 是管理员用户 Bob,令牌 AAAAAAAAAA 是标准用户 Joe。但是我对 Spring Security 没有太多经验,所以我不知道这一切是如何结合在一起的。我仍然希望能够在控制器和服务方法上使用安全注释。

有没有办法在 Spring Security 中实现这一点?

这个问题似乎是一个很好的起点,但我不确定这是否会像我预想的那样奏效RESTful Authentication via Spring

【问题讨论】:

标签: spring-mvc spring-security restful-authentication


【解决方案1】:

这将是一个从Spring-Rest-Boilerplate 开始的好地方。

  1. 第一次您必须使用 http 基本身份验证和 然后登录(发送用户名/密码),这将返回令牌。
  2. 在后续请求中,您将使用此令牌进行身份验证。
  3. 您必须向执行此操作的链添加一个过滤器 基于令牌的身份验证。

您必须想出一个令牌格式和相同的加密。理想情况下,您还需要保留令牌的到期时间,到期时间和用户名可能是令牌的一部分。使用 加密算法 像 MD5 这样的加密哈希函数并获取整个令牌的哈希值。

编辑:正如 Maciej Stępyra 所指出的,MD5 似乎已损坏,建议使用更强的哈希函数,如 SHA-256。

默认情况下,Spring 安全性会将您重定向到登录页面,但这在 REST 的情况下没有意义,因此请在配置中使用自定义 AuthenticationEntryPoint(参考 github 代码示例)。

我的令牌使用这种格式: token:username:hash:expiry

hash=MD5(用户名+magickey)

expiry=current_timestamp+mins_to_expiry

 <security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="always" entry-point-ref="**CustomAuthenticationEntryPoint**">
        <security:custom-filter ref="**authenticationTokenProcessingFilter**" position="PRE_AUTH_FILTER" />
        <security:intercept-url pattern="/**" access="isAuthenticated()" />
 </security:http>

NB:感谢 dhavaln 提供代码。我以此为参考并开发了类似的东西。

【讨论】:

  • 这看起来是一个很好的起点。谢谢! Spring Security 是否在内部将令牌映射到会话,以便您仍然可以执行诸如 @Secured(value={"ROLE_ADMIN"}) 之类的操作?
  • 是的,您可以使用,但不需要会话 REST 应该是无状态的并配置 create-session="stateless " 。在您的TokenAuthenticationFilter 中查找用户详细信息并创建一个UsernamePasswordAuthenticationToken 并使用SecurityContextHolder.getContext().setAuthentication(authentication);
  • 如何更新您的令牌?就像您将其设置为在 15 分钟后过期并且您在整个 15 分钟内一直在发送请求,您是否会强制用户再次重新登录?
  • 您可以通过多种方式实现这一点,对于第一个身份验证请求,我们发回了刷新令牌和到期时间,因此客户端 SDK 使用刷新令牌自动调用以获取新的访问令牌令牌已过期。
  • MD5 是一种散列算法,不是加密 ;) 最好使用更强的算法,例如 SHA256
【解决方案2】:

“我希望应用程序完全无状态”

我会重新考虑你想要做什么。找不到解决方案的好例子是有原因的:您根本无法拥有既无状态又安全的应用程序。此外,如果您将令牌存储在某个地方,那么您就不是无国籍的。即使您不存储令牌(例如使用 JWT 对其进行编码),如果用户将在 Web 浏览器中访问它,您也必须防止 CSRF 攻击。如果您确实按照自己的方式行事,预计会编写大量定制的安全代码(这是一件坏事)。在此处查看对此的讨论:https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii

【讨论】:

    【解决方案3】:

    在我的例子中,我发现用在多个 tomcat 节点之间共享 SecurityContext 的实现替换 org.springframework.security.web.context.SecurityContextPersistenceFilter 中的 org.springframework.security.web.context.SecurityContextRepository 更容易。客户端不断发送类似 jsessionid 的令牌,但我可以进行简单的循环负载平衡,而不必担心会话复制。

    【讨论】:

      猜你喜欢
      • 2012-11-06
      • 2016-02-10
      • 2015-11-16
      • 2016-10-01
      • 1970-01-01
      • 2017-04-05
      • 2013-10-18
      • 2015-04-29
      • 2014-11-24
      相关资源
      最近更新 更多