前言

Spring Security OAuth2 主要提供 4 个模块,其中 spring-security-oauth2-resource-server 提供 OAuth2 Resource Server 的实现,本文主要了解一些核心组件和部分内置 Filter

核心组件

SecurityFilterChain


--------------- Spring Boot 自动装配

	@Bean
	@ConditionalOnBean(JwtDecoder.class)
	SecurityFilterChain jwtSecurityFilterChain(HttpSecurity http) throws Exception {
		// 所有请求需要认证
		http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
		// 声明 资源服务器 验证的令牌格式,默认 JWT
		http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
		return http.build();
	}

------------------ 自定义
	
	@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
        return security
                .authorizeRequests(
                        request -> request
                                .mvcMatchers("/test").permitAll()
                                .anyRequest().authenticated()
                )
                .oauth2ResourceServer(
                        // 指定令牌解析的方式,比如:从 Request Head 的 token 获取
                        // 默认在 Request Head 中以 Authorization: Bearer token 的格式提供
                        config -> config.bearerTokenResolver(new HeaderBearerTokenResolver("token"))
                                .jwt()
                )
                .build();
    }
  • SecurityFilterChainSpring Security 本身的组件
  • 此处是 Spring Boot 自动装配类提供的默认实例,其中
    • oauth2ResourceServer 声明为 Resource Server
    • OAuth2ResourceServerConfigurer::jwt 指定 资源服务器 验证的令牌格式为 JWT
  • 当然也可以提供自己的 SecurityFilterChain,比如自行指定解析令牌的方式:默认从 Request Head 中以 Authorization: Bearer token 的格式解析

JwtDecoder

	@Bean
	@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
	JwtDecoder jwtDecoderByJwkKeySetUri() {
		// 基于 JwkSetUri 等创建对应的 NimbusJwtDecoder
		NimbusJwtDecoder nimbusJwtDecoder = NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri())
				.jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
		String issuerUri = this.properties.getIssuerUri();
		if (issuerUri != null) {
			nimbusJwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuerUri));
		}
		return nimbusJwtDecoder;
	}
  • Resource Server 默认接受的令牌格式为 JWT,因此 Spring Boot 会默认装配一个基于 JwkSetUri 属性的 NimbusJwtDecoder 实例
  • JwkSetUri 属性即对应 认证中心/oauth2/jwks 路径,主要是获取验签 JWT 的密钥信息

JwtAuthenticationConverter

	@Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        
        // 从 JWT 中解析的权限信息不加前缀
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthorityPrefix("");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
  • JwtAuthenticationConverter 实例负责从 JWT 中转换 认证 信息
  • 其中,JwtGrantedAuthoritiesConverter 负责转换 权限 信息
  • 一般情况这个实例不需要自定义覆盖,但是如果有需求也可以调整,比如示例中从 JWT 中转换出来的权限不需要前缀(默认前缀 SCOPE_,即 资源服务器 声明权限时需要带上此前缀)

内置 Filter

BearerTokenAuthenticationFilter

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		String token;
		try {
			// 从 request 中解析 token 信息
			token = this.bearerTokenResolver.resolve(request);
		}
		catch (OAuth2AuthenticationException invalid) {
			return;
		}

		// 构造 BearerTokenAuthenticationToken
		BearerTokenAuthenticationToken authenticationRequest = new BearerTokenAuthenticationToken(token);
		authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));

		try {
			// 令牌验证
			AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);
			Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest);
			SecurityContext context = SecurityContextHolder.createEmptyContext();
			context.setAuthentication(authenticationResult);
			SecurityContextHolder.setContext(context);
			this.securityContextRepository.saveContext(context, request, response);

			filterChain.doFilter(request, response);
		}
		catch (AuthenticationException failed) {

		}
	}

不难猜测,该过滤器负责处理需要认证的路径:解析并验证 令牌 信息

总结

spring-security-oauth2-resource-server 的组件和 Filter 相对简单,只需要负责正确的解析 令牌 并验证,在 Spring Boot 自动装配的加持下,只需要正确指定 spring.security.oauth2.resourceserver.jwt.issuer-uri 属性即可

完整 demo 示例

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐