当前位置: 首页 > 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 授权码模式的认证流程,并灵活扩展为其他授权类型(如隐式模式、密码模式)。

相关文章:

  • 加油站小程序实战教程12显示会员信息
  • 【Django】设置让局域网内的人访问
  • 忽略 CS8616 警告在 Visual Studio 2022 中【C# 8.0 】
  • Halcon应用:相机标定之应用
  • AI助理iOS开发:Copilot for Xcode 下载与安装全指南
  • Spark-SQL与Hive集成及数据分析实践
  • Android15沉浸式界面顶部有问题
  • jinjia2将后端传至前端的字典变量转换为JS变量
  • TM1640学习手册及示例代码
  • 傲来云分享,负载均衡:提升网站性能与稳定性
  • 13.QT-DateTime Edit|Dial|Slider|日期计算器|调整窗口透明度|调整窗口大小|自定义快捷键(C++)
  • 在 UE5 编辑器中,由于游戏设置 -> EV100 设置,点击播放前后的光照不同。如何保持点击播放前后的光照一致?
  • 【HDFS入门】深入解析DistCp:Hadoop分布式拷贝工具的原理与实践
  • 利用课程编辑器创新教学,提升竞争力​
  • 【Spring Boot基础】MyBatis的基础操作:日志、增删查改、列名和属性名匹配 -- 注解实现
  • Kafka 生产者的幂等性与事务特性详解
  • C++--负载均衡在线OJ
  • Java 性能优化:如何利用 APM 工具提升系统性能?
  • 怎样用 esProc 将数据集中重复内容置空
  • .NET WPF 三维模型
  • 护航民营企业出海,上海设37家维权工作站、建立近百人专家团队
  • 全国总工会成立100周年,工运历史和发展成就展将对外展出
  • 安且吉兮,西泠印社雅集吴昌硕故里
  • 18条举措!上海国际金融中心进一步提升跨境金融服务便利化
  • 美方因涉港问题对中国官员滥施非法单边制裁,外交部:强烈谴责,对等反制
  • 金价新高不断,上金所再发风险提示,黄金能否持续闪耀?