Spring Security OAuth2 JWT 资源服务器(旧版)具有 NULL Principal
Posted
技术标签:
【中文标题】Spring Security OAuth2 JWT 资源服务器(旧版)具有 NULL Principal【英文标题】:Spring Security OAuth 2 JWKS Resource Server (Legacy) has NULL Principal 【发布时间】:2020-10-28 18:01:31 【问题描述】:我需要设置一个旧的 Spring-Boot 1.5 项目来充当 OAuth2 资源服务器,使用公开的 JWKS 来验证每个请求的所有传入 JWT。
我关注/查看的链接和文章是:
https://projects.spring.io/spring-security-oauth/docs/oauth2.html https://www.baeldung.com/spring-security-oauth2-jws-jwk Spring Security OAuth with JWK Example我的pom.xml
中有以下依赖项:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.22.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>project</groupId>
<artifactId>project-resource</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Project Resource</name>
<description>Project Resource</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
</dependency>
<!--https://projects.spring.io/spring-security-oauth/docs/oauth2.html-->
<!--https://projects.spring.io/spring-security-oauth/docs/oauth2.html#resource-server-configuration-->
<!--https://github.com/spring-projects/spring-security-oauth/tree/master/tests/annotation/resource-->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
我将其配置为充当资源服务器并在 application.yml
中使用 JWKS uri:
security:
oauth2:
resource:
jwk:
key-set-uri: http://sso.server/.well-known/jwks.json
主类就这么简单:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
@SpringBootApplication
@EnableResourceServer
public class ProjectResourceApplication
public static void main(String[] args)
SpringApplication.run(ProjectResourceApplication.class, args);
为了使用来自另一个域的 API,我还必须提供这个CorsFilter
,
因为简单的 httpSecurity.cors() 不起作用。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter extends OncePerRequestFilter
@Value("$custom.cors.allowOrigin:*")
private String allowOrigin;
@Value("$custom.cors.allowMethods:GET, POST, PUT, DELETE, OPTIONS")
private String allowMethods;
@Value("$custom.cors.allowHeaders:Content-Type,Authorization")
private String allowHeaders;
@Value("$custom.cors.allowCredentials:true")
private String allowCredentials;
@Value("$custom.cors.maxAge:3600")
private String maxAge;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
response.addHeader("Access-Control-Allow-Origin", allowOrigin);
if (HttpMethod.OPTIONS.matches(request.getMethod()))
response.addHeader("Access-Control-Allow-Methods", allowMethods);
response.addHeader("Access-Control-Allow-Headers", allowHeaders);
response.addHeader("Access-Control-Allow-Credentials", allowCredentials);
response.addHeader("Access-Control-Max-Age", maxAge);
response.setStatus(HttpServletResponse.SC_OK);
else
filterChain.doFilter(request, response);
授权工作正常,这意味着令牌已通过 JWKS 正确验证, 但是 Principal 始终为 null。
例如:
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
public class PrincipalController
@GetMapping("/principal")
public Principal getPrincipal(@AuthenticationPrincipal Principal principal)
return principal;
有什么错误或遗漏吗?此外,如果可能的话,我还希望有一个自定义对象作为 Principal。 Rosource 服务器是否还需要有关客户端的信息才能提供委托人?如在https://github.com/spring-projects/spring-security-oauth/issues/1012
【问题讨论】:
【参考方案1】:一种解决方案是添加UserInfoTokenServices 类型的@Bean
,如下所述。
可以使用自定义 Principal 和 Authorities 提取器进一步自定义此类 @Bean
。
【讨论】:
以上是关于Spring Security OAuth2 JWT 资源服务器(旧版)具有 NULL Principal的主要内容,如果未能解决你的问题,请参考以下文章
Spring-Security OAuth2 设置 - 无法找到 oauth2 命名空间处理程序
Spring Security OAuth2 v5:NoSuchBeanDefinitionException:'org.springframework.security.oauth2.jwt.Jwt
针对授权标头的Spring Security OAuth2 CORS问题