Spring Security OAuth2.1现代化身份认证核心概念Spring Security OAuth2.1 是 Spring Security 提供的现代化身份认证解决方案支持 OAuth 2.1 规范提供了完整的认证和授权功能。OAuth2.1 对 OAuth 2.0 进行了改进移除了不安全的隐式流推荐使用授权码流并增强了安全性。OAuth2.1 的核心组件Authorization Server授权服务器负责颁发令牌Resource Server资源服务器保护受保护的资源Client客户端应用请求访问资源Resource Owner资源所有者授权客户端访问其资源授权服务器配置// 授权服务器配置 Configuration EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private final AuthenticationManager authenticationManager; private final DataSource dataSource; private final PasswordEncoder passwordEncoder; public AuthorizationServerConfig(AuthenticationManager authenticationManager, DataSource dataSource, PasswordEncoder passwordEncoder) { this.authenticationManager authenticationManager; this.dataSource dataSource; this.passwordEncoder passwordEncoder; } Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(dataSource) .withClient(client-id) .secret(passwordEncoder.encode(client-secret)) .authorizedGrantTypes(authorization_code, refresh_token) .scopes(read, write) .redirectUris(http://localhost:8080/callback) .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(86400); } Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .authenticationManager(authenticationManager) .tokenStore(tokenStore()) .approvalStore(approvalStore()) .authorizationCodeServices(authorizationCodeServices()); } Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security .tokenKeyAccess(permitAll()) .checkTokenAccess(isAuthenticated()) .allowFormAuthenticationForClients(); } Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } Bean public ApprovalStore approvalStore() { return new JdbcApprovalStore(dataSource); } Bean public AuthorizationCodeServices authorizationCodeServices() { return new JdbcAuthorizationCodeServices(dataSource); } }资源服务器配置// 资源服务器配置 Configuration EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { Override public void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers(/api/public/**).permitAll() .antMatchers(/api/users/**).hasAuthority(SCOPE_read) .antMatchers(/api/admin/**).hasAuthority(SCOPE_write) .anyRequest().authenticated(); } Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources .resourceId(resource-id) .tokenStore(tokenStore()); } Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource()); } Bean ConfigurationProperties(prefix spring.datasource) public DataSource dataSource() { return DataSourceBuilder.create().build(); } }安全配置// 安全配置 Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Autowired private UserDetailsService userDetailsService; Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers(/oauth/**, /login/**, /logout/**).permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage(/login) .permitAll() .and() .logout() .logoutSuccessUrl(/login?logout) .permitAll(); } Override Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }JWT 令牌配置// JWT 令牌配置 Configuration public class JwtTokenConfig { Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter new JwtAccessTokenConverter(); converter.setSigningKey(my-signing-key); return converter; } Bean public TokenEnhancer tokenEnhancer() { return (accessToken, authentication) - { MapString, Object additionalInfo new HashMap(); additionalInfo.put(customClaim, customValue); ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return accessToken; }; } }客户端配置// OAuth2 客户端配置 Configuration public class OAuth2ClientConfig { Bean ConfigurationProperties(spring.security.oauth2.client.registration.my-client) public ClientRegistration clientRegistration() { return ClientRegistration.withRegistrationId(my-client) .clientId(client-id) .clientSecret(client-secret) .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri({baseUrl}/login/oauth2/code/{registrationId}) .scope(read, write) .authorizationUri(http://localhost:8080/oauth/authorize) .tokenUri(http://localhost:8080/oauth/token) .userInfoUri(http://localhost:8080/userinfo) .userNameAttributeName(IdTokenClaimNames.SUB) .clientName(My Client) .build(); } Bean public OAuth2AuthorizedClientService authorizedClientService( ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) { return new DefaultOAuth2AuthorizedClientService(clientRegistrationRepository); } Bean public OAuth2AuthorizedClientRepository authorizedClientRepository() { return new InMemoryOAuth2AuthorizedClientRepository(); } }自定义用户信息// 自定义用户详情服务 Service public class CustomUserDetailsService implements UserDetailsService { Autowired private UserRepository userRepository; Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user userRepository.findByUsername(username) .orElseThrow(() - new UsernameNotFoundException(User not found)); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, getAuthorities(user.getRoles()) ); } private Collection? extends GrantedAuthority getAuthorities(ListString roles) { return roles.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); } } // 用户实体 Entity public class User { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String username; private String password; private boolean enabled; ElementCollection private ListString roles new ArrayList(); // getters and setters }刷新令牌// 刷新令牌服务 Service public class TokenRefreshService { Autowired private OAuth2RestTemplate restTemplate; public OAuth2AccessToken refreshToken(String refreshToken) { OAuth2ClientContext clientContext new DefaultOAuth2ClientContext(); ResourceOwnerPasswordResourceDetails resourceDetails new ResourceOwnerPasswordResourceDetails(); resourceDetails.setClientId(client-id); resourceDetails.setClientSecret(client-secret); resourceDetails.setAccessTokenUri(http://localhost:8080/oauth/token); resourceDetails.setRefreshToken(refreshToken); OAuth2AccessToken token restTemplate.getOAuth2ClientContext().getAccessToken(); if (token.isExpired()) { token restTemplate.getOAuth2ClientContext().getAccessToken(); } return token; } }安全端点// 用户信息端点 RestController RequestMapping(/userinfo) public class UserInfoController { GetMapping public ResponseEntityMapString, Object getUserInfo(Principal principal) { MapString, Object userInfo new HashMap(); userInfo.put(username, principal.getName()); userInfo.put(authorities, ((Authentication) principal).getAuthorities()); return ResponseEntity.ok(userInfo); } } // 健康检查端点 RestController RequestMapping(/health) public class HealthController { GetMapping public ResponseEntityMapString, Object health() { return ResponseEntity.ok(Map.of(status, UP)); } }最佳实践使用授权码流推荐使用授权码流避免隐式流安全存储令牌使用数据库存储令牌避免内存存储设置合理的令牌过期时间根据业务需求设置合适的过期时间使用 HTTPS确保所有 OAuth2 通信使用 HTTPS限制客户端权限为每个客户端分配最小必要权限审计日志记录认证和授权事件定期轮换密钥定期更换签名密钥实际应用场景单点登录多个应用共享同一个认证系统API 安全保护 RESTful API第三方授权允许第三方应用访问用户数据移动应用认证为移动应用提供安全认证总结Spring Security OAuth2.1 提供了现代化的身份认证解决方案支持 OAuth 2.1 规范提供了完整的认证和授权功能。通过合理配置和使用可以构建安全、可靠的身份认证系统保护应用和用户数据的安全。别叫我大神叫我 Alex 就好。这其实可以更优雅一点合理的 OAuth2.1 配置让身份认证变得更加安全和可靠。