Spring-Security

在 Spring Security 中获取当前用户

1、概览 本文介绍了如何在 Spring Security 中检索当前用户详细信息。 2、从 Bean 中获取用户 检索当前已通过身份认证用户(Principal)的最简单方式是调用 SecurityContextHolder 的静态方法: Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String currentPrincipalName = authentication.getName(); 该代码需要改进的地方在于,在尝试访问之前,首先要检查是否存在已通过身份认证的用户: Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (!(authentication instanceof AnonymousAuthenticationToken)) { String currentUserName = authentication.getName(); return currentUserName; } 当然,这样的静态调用也有缺点,代码的可测试性降低了。 3、在 Controller 中获取用户 在 @Controller 中,可以直接将 Principal 定义为方法参数,这样框架就能正确地解析: @Controller public class GetUserWithPrincipalController { @RequestMapping(value = "/username", method = RequestMethod.GET) @ResponseBody public String currentUserName(Principal principal) { return principal.getName(); } } 或者,也可以使用 Authentication Token: @Controller public class GetUserWithAuthenticationController { @RequestMapping(value = "/username", method = RequestMethod.

Spring Security - 角色和权限

1、概览 本文将带你了解如何在 Spring Security 中正确地实现 角色(Role) 和 权限(Privilege)。 2、用户、角色和权限 有如下 3 个实体: User:代表用户 Role:代表用户在系统中的高级角色。每个角色都有一组低级权限。 Privilege:代表系统中较低级别的、细粒度的特权/权限。 User 如下: @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String firstName; private String lastName; private String email; private String password; private boolean enabled; private boolean tokenExpired; @ManyToMany @JoinTable( name = "users_roles", joinColumns = @JoinColumn( name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn( name = "role_id", referencedColumnName = "id")) private Collection<Role> roles; } 如上,用户包含角色和一些额外的细节,这些细节对于适当的注册机制来说是必要的。

在 Security Filter Chain 中自定义 Filter

1、概览 本文将带你了解如何在 Spring Security Filter Chain(过滤器链)中定义一个自定义过 Filter(过滤器)。 2、创建 Filter Spring Security 默认提供了许多 Filter,这些 Filter 在大多数情况下已经足够。 当然,有时也需要在链中创建一个新的 Filter 来实现新功能。 首先,可以实现 org.springframework.web.filter.GenericFilterBean。 GenericFilterBean 是一个简单的 javax.servlet.Filter 实现,它还实现了一系列的 Aware 接口,可以感知到 Spring 容器中的一些组件。 只需实现一个方法: public class CustomFilter extends GenericFilterBean { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); } } 3、在 Security Config 中配置 Filter 可以通过 XML 或 Java 配置把 Filter 配置到 Spring Security Filter Chain 中。

Spring Security - OAuth2 登录

1、概览 Spring Security 5 开始,引入了一个新的 OAuth2LoginConfigurer 类,可以用它来配置外部授权服务器(Authorization Server)。 本文主要带你了解 oauth2Login() 方法的一些可用配置选项。 2、Maven 依赖 在 Spring Boot 项目中,只需添加 spring-boot-starter-oauth2-client Starter 即可: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> <version>2.3.3.RELEASE</version> </dependency> 在非 Spring Boot 项目中,除了标准的 Spring 和 Spring Security 依赖外,还需要显式添加 spring-security-oauth2-client 和 spring-security-oauth2-jose 依赖: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-client</artifactId> <version>5.3.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-jose</artifactId> <version>5.3.4.RELEASE</version> </dependency> 3、客户端设置 在 Spring Boot 项目中,只需为每个要配置的客户端添加几个标准属性即可。 接下来,我们要配置使用 Google 和 Facebook 作为 Authentication Provider 注册的客户端登录。 3.1、获取客户端凭证 要获取 Google OAuth2 身份认证的客户端凭证,请访问 Google API 控制台 的 “Credentials” 部分。

Spring Security 方法安全(Method Security)简介

1、概览 简而言之,Spring Security 支持方法级别的授权语义。可以通过限制哪些角色可以执行特定方法等方式来确保 Service 层的安全。 2、启用 Method Security 要使用 Spring Method Security,需要添加 spring-security-config 依赖: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> 可以在 Maven Central 上找到它的最新版本。 如果使用的是 Spring Boot,可以添加 spring-boot-starter-security 依赖,其中包括 spring-security-config: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 同样,它的最新版本也可以在 Maven Central 中找到。 接下来,需要启用全局 Method Security: @Configuration @EnableGlobalMethodSecurity( prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { } prePostEnabled 属性可启用 Spring Security Pre/Post 注解。 securedEnabled 属性决定是否启用 @Secured 注解。 jsr250Enabled 属性允许使用 @RoleAllowed 注解。 3、应用 Method Security 3.

使用 Spring Security OAuth2 实现 SSO 单点登录

1、概览 本文将带你了解如何使用 Spring Security OAuth 和 Spring Boot 以及 Keycloak 作为授权服务器来实现单点登录(SSO)。 我们会使用 4 个不同的应用: 授权服务器 - 中央认证机制 资源服务器 - Foo 资源的提供者 两个客户端应用 - 使用 SSO 的应用 简单地说,当用户试图通过一个客户端应用访问资源时,他们会被重定到授权服务器进行身份认证。Keycloak 会对用户进行登录,在登录第一个应用后,如果使用同一浏览器访问第二个客户端应用,用户无需再次输入凭据。 使用 OAuth2 的授权码(Authorization Code)模式。 Spring Security 将此功能称为 OAuth 2.0 登录,而 Spring Security OAuth 将其称为 SSO。 2、授权服务器 以前,通过 Spring Security OAuth 可以将授权服务器设置为 Spring 应用。 不过,Spring Security OAuth 已被 Spring 弃用,现在可以使用 Keycloak 作为授权服务器。 因此,这次我们在 Spring Boot 应用中把授权服务器设置为嵌入式 Keycloak 服务器。 在 预配置 中,我们将定义两个客户端,即 ssoClient-1 和 ssoClient-2,分别对应每个客户端应用。

使用 Spring Security OAuth2 实现 SSO 单点登录(传统技术栈)

1、概览 本文将带你了解如何使用 Spring Security OAuth 和 Spring Boot 实现单点登录(SSO)。 我们会使用三个不同的应用: 授权服务器 - 中央认证机制 两个客户端应用:使用 SSO 的应用 简单来说,当用户试图访问客户端应用中受保护的页面时,他们会被重定向到过身份认证服务器进行身份验。使用 OAuth2 的 “授权码(Authorization Code)模式”。 注:本文使用的是 Spring OAuth 传统技术。如果你想查看新版 Spring Security 的版本,请参阅《使用 Spring Security OAuth2 实现 SSO 单点登录》。 2、客户端应用 从客户端应用开始。当然,使用 Spring Boot 构建。 2.1、Maven 依赖 在 pom.xml 中加入以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency> 2.2、Security 配置 接下来是最重要的部分,即客户端应用的 Security 配置:

Spring Security 和 Apache Shiro

1、概览 在应用开发中,尤其是在企业级 Web 和移动应用领域,安全是一个首要问题。 本文将带你了解、比较两种流行的 Java 安全框架 - Apache Shiro 和 Spring Security。 2、背景 Apache Shiro 诞生于 2004 年,原名 JSecurity,2008 年被 Apache 基金会接受。迄今为止,它已发布了多个版本,最新版本为 1.13.0。 Spring Security 起源于 2003 年的 Acegi,在 2008 年首次公开发布时被纳入 Spring 框架。自诞生以来,它经历了多次迭代,目前的 GA 版本是 6.2.0。 这两种技术都提供身份认证和授权支持,以及加密和 Session 管理解决方案。此外,Spring Security 还提供了一流的保护,防范诸如 CSRF 和会话固定等攻击。 接下来,我们将通过使用 FreeMarker 的 Spring Boot 应用来演示如何使用这两种技术进行身份认证和授权。 3、配置 Apache Shiro 首先,来看看这两种框架的配置有何不同。 3.1、Maven 依赖 添加 shiro-spring-boot-web-starter 和 shiro-core 依赖: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.5.3</version> </dependency> 依赖的最新版本可在 Maven Central 上找到。

使用 Spring Security 构建 OAuth 2.0 资源服务器

1、概览 本文将带你了解如何使用 Spring Security 构建 OAuth 2.0 资源服务器(使用 JWT 和 Opaque Token,这两种由 Spring Security 支持的 Bearer Token)。 2、背景介绍 2.1、JWT 和 Opaque Token 是什么? JWT 或 JSON Web Token 是一种以广泛接受的 JSON 格式安全传输敏感信息的方式。其中包含的信息可能是关于用户的,也可能是关于 Token 本身的,例如其 expiry(有效期)和 issuer(签发者)。 Opaque Token 顾名思义,它所携带的信息是不透明的。Token 只是一个标识符,指向存储在授权服务器上的信息;它通过服务器端的自省(Introspection)进行验证。 2.2、资源服务器是什么? 在 OAuth 2.0 中,资源服务器是通过 OAuth Token 保护资源的应用。这些 Token 由授权服务器(通常是客户端应用)签发。资源服务器的工作是在向客户端提供资源之前验证 Token。 令牌的有效性由几个因素决定: 该令牌是否来自配置的授权服务器? 是否未过期? 该资源是否为预期受众(audience)提供服务? Token 是否具有访问所请求资源的必要权限? 来看一下 授权码模式 的顺序图,并观察所有相关的参与者: 正如在步骤 8 中看到的,当客户端应用调用资源服务器的 API 访问受保护的资源时,它首先会转到授权服务器,以验证请求的 Authorization: Bearer Header 信息中包含的 Token,然后响应客户端。 本文的重点是第 9 步。

使用 Spring Security 防止 CSRF 攻击

1、概览 本文将带你了解什么是跨站请求伪造(CSRF)攻击?以及如何使用 Spring Security 来防范这些攻击。 2、两种简单的 CSRF 攻击行为 CSRF 攻击有多种形式。 2.1、GET 示例 假如下面这个 GET 请求,用于一个已登录的用户向指定的银行账户 1234 转账: GET http://bank.com/transfer?accountNo=1234&amount=100 如果攻击者想把钱从受害者的账户转到自己的账户(5678),他需要让受害者触发请求: GET http://bank.com/transfer?accountNo=5678&amount=1000 有多种方法可以实现这一点: 链接 - 攻击者可以说服/诱导受害者点击该链接,例如执行转账: <a href="http://bank.com/transfer?accountNo=5678&amount=1000"> 点击展示美女图片 </a> 图片 - 攻击者可能会使用 <img/> 标签,将目标 URL 作为图片来源。换句话说,甚至不需要点击。请求将在页面加载时自动执行: <img src="http://bank.com/transfer?accountNo=5678&amount=1000"/> 所以,涉及到敏感的业务,千万不能用 GET 请求。 2.2、POST 示例 假设转账 API 是一个 POST 请求。 POST http://bank.com/transfer accountNo=1234&amount=100 在这种情况下,<a> 和 <img/> 标签都不起作用。 攻击者需要使用 <form>: <form action="http://bank.com/transfer" method="POST"> <input type="hidden" name="accountNo" value="5678"/> <input type="hidden" name="amount" value="1000"/> <input type="submit" value="Show Kittens Pictures"/> </form> 然后,使用 JavaScript 自动提交表单: