当前位置: 首页 > news >正文

Spring Security OAuth2.1:现代化身份认证

Spring Security OAuth2.1:现代化身份认证

核心概念

Spring Security OAuth2.1 是 Spring Security 提供的现代化身份认证解决方案,支持 OAuth 2.1 规范,提供了完整的认证和授权功能。OAuth2.1 对 OAuth 2.0 进行了改进,移除了不安全的隐式流,推荐使用授权码流,并增强了安全性。

OAuth2.1 的核心组件

  1. Authorization Server:授权服务器,负责颁发令牌
  2. Resource Server:资源服务器,保护受保护的资源
  3. Client:客户端应用,请求访问资源
  4. 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) -> { Map<String, 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(List<String> 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 List<String> 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 ResponseEntity<Map<String, Object>> getUserInfo(Principal principal) { Map<String, 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 ResponseEntity<Map<String, Object>> health() { return ResponseEntity.ok(Map.of("status", "UP")); } }

最佳实践

  1. 使用授权码流:推荐使用授权码流,避免隐式流
  2. 安全存储令牌:使用数据库存储令牌,避免内存存储
  3. 设置合理的令牌过期时间:根据业务需求设置合适的过期时间
  4. 使用 HTTPS:确保所有 OAuth2 通信使用 HTTPS
  5. 限制客户端权限:为每个客户端分配最小必要权限
  6. 审计日志:记录认证和授权事件
  7. 定期轮换密钥:定期更换签名密钥

实际应用场景

  • 单点登录:多个应用共享同一个认证系统
  • API 安全:保护 RESTful API
  • 第三方授权:允许第三方应用访问用户数据
  • 移动应用认证:为移动应用提供安全认证

总结

Spring Security OAuth2.1 提供了现代化的身份认证解决方案,支持 OAuth 2.1 规范,提供了完整的认证和授权功能。通过合理配置和使用,可以构建安全、可靠的身份认证系统,保护应用和用户数据的安全。

别叫我大神,叫我 Alex 就好。这其实可以更优雅一点,合理的 OAuth2.1 配置让身份认证变得更加安全和可靠。

http://www.jsqmd.com/news/779430/

相关文章:

  • 构建基于异步任务队列与AI代理的代码自愈系统
  • 世界地球日|从“发得出”迈向“用得好”,电能质量装置如何守护绿色低碳?
  • 一个数据包让服务器蓝屏?MS12-020漏洞实战,微软补丁救场
  • Windows 一键部署 OpenClaw 教程|5 分钟启用本地 AI 智能体,简化全环节配置
  • 2026届必备的六大降重复率方案横评
  • 25_通过参考视频快速生成提示词——高效复刻精彩分镜
  • Java 性能调优:火焰图分析与优化
  • 高手进阶(三):写完代码该做什么?代码审查别再只用/review:Claude Code三档审查体系,<1%误报率照抄配置
  • CST微波工作室新手避坑指南:从Brick建模到材料库调用的5个实用技巧
  • 海思视觉--flash配置文件
  • 【DeepSeek】Socket API 支持的协议族
  • 动态多模态潜在空间推理框架DMLR设计与实现
  • 20254106 实验三《Python程序设计》实验报告
  • 解决SEGGER_RTT_printf无法打印浮点数问题
  • 使用技巧(四):还在手写Hooks脚本?五个现成插件装好就生效,拦截删文件、护密钥、强制测试
  • aghub:GitHub开发者效率工具集,批量克隆、仓库管理与自动化实战
  • 2026年晶晨股份数字IC笔试试卷带答案
  • 搜维尔科技:利用MANUS数据手套扩展人形机器人操作数据采集规模
  • 2026年Java面试最全避坑指南:从基础、并发、JVM到微服务,这一篇就够了
  • 公司内网 git clone提示fatel失败
  • 写论文怎么给英文降AI?从97%降至8%的4种高效方法(附实测指南) - 殷念写论文
  • 基于51单片机智能声光双控红外人体感应路灯台灯路灯设计18-785
  • 从 C++ 到 Rust:不是更好的模样,而是另一套答案
  • 20260508 0
  • ESP32无人机远程识别模块:完整开源架构与安全集成实现指南
  • Snap.Hutao:免费高效的原神工具箱完全使用指南
  • 黑客赚钱的路子有多野?CTF逆向入门指南
  • Rocky linux 10.1 ARM版本系统安装
  • 如何快速入门 Kubernetes 网络配置?
  • 户外徒步戴运动耳机哪款好?盘点十款实用性价比运动耳机测评分享