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

spring security +kotlin 实现oauth2.0 认证

基于OAuth 2.0的认证功能实现(Kotlin + Spring Security)

以下是使用 AbstractAuthenticationProcessingFilterAuthenticationProviderAbstractAuthenticationTokenAuthenticationSuccessHandler 实现 OAuth 2.0 认证的完整代码设计。


1. 自定义认证令牌:OAuth2AuthenticationToken

import org.springframework.security.authentication.AbstractAuthenticationToken
import org.springframework.security.core.GrantedAuthorityclass OAuth2AuthenticationToken(private val code: String,          // 授权码(Credentials)private val clientId: String,      // 客户端ID(Principal)authorities: List<GrantedAuthority> = emptyList()
) : AbstractAuthenticationToken(authorities) {init {isAuthenticated = false       // 初始状态未认证}override fun getPrincipal(): Any = clientIdoverride fun getCredentials(): Any = code// 认证成功后调用此方法设置权限fun setAuthenticated(authorized: Boolean, authorities: List<GrantedAuthority>) {require(authorized) { "Cannot set to unauthenticated" }super.setAuthenticated(true)super.setDetails(authorities)}
}

2. 自定义认证过滤器:OAuth2AuthenticationFilter

import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponseclass OAuth2AuthenticationFilter(defaultFilterProcessesUrl: String) :AbstractAuthenticationProcessingFilter(defaultFilterProcessesUrl) {override fun attemptAuthentication(request: HttpServletRequest,response: HttpServletResponse): Authentication {// 从请求中提取 OAuth2 参数val code = request.getParameter("code") ?: throw MissingCodeException()val clientId = request.getParameter("client_id") ?: throw MissingClientIdException()// 创建未认证的 Tokenval authRequest = OAuth2AuthenticationToken(code, clientId)// 提交给 AuthenticationManager 进行认证return authenticationManager.authenticate(authRequest)}
}

3. 自定义认证提供器:OAuth2AuthenticationProvider

import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.SimpleGrantedAuthorityclass OAuth2AuthenticationProvider(private val oAuth2Service: OAuth2Service // 自定义的 OAuth2 服务
) : AuthenticationProvider {override fun supports(authentication: Class<*>): Boolean {return OAuth2AuthenticationToken::class.java.isAssignableFrom(authentication)}override fun authenticate(authentication: Authentication): Authentication {val token = authentication as OAuth2AuthenticationTokenval code = token.credentials as Stringval clientId = token.principal as String// 调用 OAuth2 服务验证授权码并获取用户信息val userInfo = oAuth2Service.exchangeCodeForUserInfo(code, clientId)// 构建认证成功的 Tokenreturn OAuth2AuthenticationToken(code = code,clientId = clientId,authorities = userInfo.roles.map { SimpleGrantedAuthority("ROLE_$it") }).apply {setAuthenticated(true, authorities)details = userInfo // 附加用户详细信息}}
}

4. 自定义成功处理器:OAuth2AuthenticationSuccessHandler

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponseclass OAuth2AuthenticationSuccessHandler(private val objectMapper: ObjectMapper
) : AuthenticationSuccessHandler {override fun onAuthenticationSuccess(request: HttpServletRequest,response: HttpServletResponse,authentication: Authentication) {response.contentType = "application/json"response.characterEncoding = "UTF-8"// 生成响应数据(如 JWT 或用户信息)val userInfo = authentication.details as UserInfoval accessToken = generateJwtToken(userInfo)val result = mapOf("access_token" to accessToken,"user_id" to userInfo.id,"roles" to userInfo.roles)response.writer.write(objectMapper.writeValueAsString(result))}private fun generateJwtToken(userInfo: UserInfo): String {// 实现 JWT 生成逻辑(示例使用 jjwt)return Jwts.builder().setSubject(userInfo.id).claim("roles", userInfo.roles).signWith(SignatureAlgorithm.HS256, "your-secret-key").compact()}
}

5. 配置 Spring Security

@Configuration
@EnableWebSecurity
class SecurityConfig(private val oAuth2Service: OAuth2Service,private val objectMapper: ObjectMapper
) : WebSecurityConfigurerAdapter() {// 注册认证过滤器@Beanfun oauth2Filter(): OAuth2AuthenticationFilter {val filter = OAuth2AuthenticationFilter("/oauth2/login")filter.setAuthenticationSuccessHandler(successHandler())filter.setAuthenticationManager(authenticationManagerBean())return filter}// 注册认证提供器@Beanoverride fun authenticationManagerBean(): AuthenticationManager {return ProviderManager(listOf(oAuth2AuthenticationProvider()))}@Beanfun oAuth2AuthenticationProvider(): OAuth2AuthenticationProvider {return OAuth2AuthenticationProvider(oAuth2Service)}@Beanfun successHandler(): OAuth2AuthenticationSuccessHandler {return OAuth2AuthenticationSuccessHandler(objectMapper)}override fun configure(http: HttpSecurity) {http.csrf().disable().authorizeRequests().antMatchers("/oauth2/login").permitAll().anyRequest().authenticated().and().addFilterBefore(oauth2Filter(), UsernamePasswordAuthenticationFilter::class.java)}
}

6. 辅助类定义

// OAuth2 服务接口
interface OAuth2Service {fun exchangeCodeForUserInfo(code: String, clientId: String): UserInfo
}// 用户信息数据类
data class UserInfo(val id: String,val name: String,val roles: List<String>
)// 自定义异常
class MissingCodeException : AuthenticationException("Missing 'code' parameter")
class MissingClientIdException : AuthenticationException("Missing 'client_id' parameter")

核心流程说明

  1. 客户端请求
    发送请求到 /oauth2/login?code=xxx&client_id=client1,携带授权码和客户端 ID。

  2. 过滤器拦截
    OAuth2AuthenticationFilter 提取参数并创建 OAuth2AuthenticationToken

  3. 认证提供器处理
    OAuth2AuthenticationProvider 调用 OAuth2 服务验证授权码,返回用户信息并构建认证成功的 Token。

  4. 成功响应
    OAuth2AuthenticationSuccessHandler 生成 JWT 令牌并返回 JSON 响应。


安全增强建议

  1. HTTPS 强制使用

    http.requiresChannel().anyRequest().requiresSecure()
    
  2. 令牌有效期管理

    Jwts.builder().setExpiration(Date(System.currentTimeMillis() + 3600 * 1000))
    
  3. 密钥安全存储
    使用环境变量或配置服务器管理密钥:

    @Value("\${jwt.secret}")
    private lateinit var jwtSecret: String
    

通过以上设计,可实现基于 OAuth 2.0 授权码模式的认证流程,并灵活扩展为其他授权类型(如隐式模式、密码模式)。

http://www.xdnf.cn/news/56341.html

相关文章:

  • 问题 | RAIM + LSTM 你怎么看???
  • 【图像轮廓特征查找】图像处理(OpenCV) -part8
  • Linux深度探索:进程管理与系统架构
  • 碰一碰发视频源码,碰一碰发视频OEM
  • MySQL快速入门篇---表的操作
  • 【图片转PDF工具】如何批量将文件夹里的图片以文件夹为单位批量合并PDF文档,基于WPF实现步骤及总结
  • 深入理解自监督学习(Self-Supervised Learning):理论与实践
  • Spring MVC
  • Web3核心技术解析:从区块链到C++实践
  • 【沉浸式求职学习day21】【常用类分享,完结!】
  • 【Hive入门】Hive概述:大数据时代的数据仓库桥梁
  • 基于亚马逊云科技 Amazon Bedrock Tool Use 实现 Generative UI
  • Java抽象类、接口和内部类介绍
  • 实例变量与静态变量的区别
  • 24、ASP.NET⻚⾯之间传递值的⼏种⽅式
  • idea2024.1双击快捷方式打不开
  • 室外摄像头异常自检指南+视频监控系统EasyCVR视频质量诊断黑科技
  • 【Linux】线程安全与线程同步
  • C#+Visual Studio 2022为AutoCAD 2022开发插件并显示在Ribbon选项卡
  • 【网络编程】从零开始彻底了解网络编程(三)
  • 榕壹云预约咨询系统:基于ThinkPHP+MySQL+UniApp打造的灵活预约小程序解决方案
  • 解决方案评测|告别复杂配置!基于阿里云云原生应用开发平台CAP快速部署Bolt.diy
  • 使用 Electron 打包可执行文件和资源:完整实战教程
  • [QMT量化交易小白入门]-四十六、年化收益率118%的回测参数,如何用贪心算法挑选50个两两相关性最小的ETF组合
  • 【Java面试笔记:基础】2.Exception和Error有什么区别?
  • XSS详解
  • 神经网络直接逆控制:神经网络与控制的结合入门级结合
  • 树莓派超全系列教程文档--(38)config.txt视频配置
  • SpringBoot中PDF处理完全指南
  • JVM学习