295 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			295 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 
								 | 
							
								using Microsoft.AspNetCore.Mvc;
							 | 
						||
| 
								 | 
							
								using FutureMailAPI.Services;
							 | 
						||
| 
								 | 
							
								using FutureMailAPI.DTOs;
							 | 
						||
| 
								 | 
							
								using FutureMailAPI.Models;
							 | 
						||
| 
								 | 
							
								using FutureMailAPI.Extensions;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace FutureMailAPI.Controllers
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    [ApiController]
							 | 
						||
| 
								 | 
							
								    [Route("api/v1/oauth")]
							 | 
						||
| 
								 | 
							
								    public class OAuthController : ControllerBase
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        private readonly IOAuthService _oauthService;
							 | 
						||
| 
								 | 
							
								        private readonly ILogger<OAuthController> _logger;
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public OAuthController(IOAuthService oauthService, ILogger<OAuthController> logger)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _oauthService = oauthService;
							 | 
						||
| 
								 | 
							
								            _logger = logger;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// OAuth登录端点
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpPost("login")]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> Login([FromBody] OAuthLoginDto loginDto)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var result = await _oauthService.LoginAsync(loginDto);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return Ok(result);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return BadRequest(result);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "OAuth登录时发生错误");
							 | 
						||
| 
								 | 
							
								                return StatusCode(500, new { message = "服务器内部错误" });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 创建OAuth客户端
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpPost("clients")]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> CreateClient([FromBody] OAuthClientCreateDto createDto)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                // 从OAuth中间件获取当前用户ID
							 | 
						||
| 
								 | 
							
								                var userId = HttpContext.GetCurrentUserId();
							 | 
						||
| 
								 | 
							
								                if (!userId.HasValue)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return Unauthorized(new { message = "未授权访问" });
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                var result = await _oauthService.CreateClientAsync(userId.Value, createDto);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return Ok(result);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return BadRequest(result);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "创建OAuth客户端时发生错误");
							 | 
						||
| 
								 | 
							
								                return StatusCode(500, new { message = "服务器内部错误" });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 获取OAuth客户端信息
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpGet("clients/{clientId}")]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> GetClient(string clientId)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var result = await _oauthService.GetClientAsync(clientId);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return Ok(result);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return NotFound(result);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "获取OAuth客户端信息时发生错误");
							 | 
						||
| 
								 | 
							
								                return StatusCode(500, new { message = "服务器内部错误" });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// OAuth授权端点
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpGet("authorize")]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> Authorize([FromQuery] OAuthAuthorizationRequestDto request)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                // 从OAuth中间件获取当前用户ID
							 | 
						||
| 
								 | 
							
								                var userId = HttpContext.GetCurrentUserId();
							 | 
						||
| 
								 | 
							
								                if (!userId.HasValue)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    // 如果用户未登录,重定向到登录页面
							 | 
						||
| 
								 | 
							
								                    var loginRedirectUri = $"/api/v1/auth/login?redirect_uri={Uri.EscapeDataString(request.RedirectUri)}";
							 | 
						||
| 
								 | 
							
								                    if (!string.IsNullOrEmpty(request.State))
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        loginRedirectUri += $"&state={request.State}";
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    return Redirect(loginRedirectUri);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                var result = await _oauthService.AuthorizeAsync(userId.Value, request);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    // 重定向到客户端,携带授权码
							 | 
						||
| 
								 | 
							
								                    var redirectUri = $"{request.RedirectUri}?code={result.Data.Code}";
							 | 
						||
| 
								 | 
							
								                    if (!string.IsNullOrEmpty(request.State))
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        redirectUri += $"&state={request.State}";
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    return Redirect(redirectUri);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                // 错误重定向
							 | 
						||
| 
								 | 
							
								                var errorRedirectUri = $"{request.RedirectUri}?error={result.Message}";
							 | 
						||
| 
								 | 
							
								                if (!string.IsNullOrEmpty(request.State))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    errorRedirectUri += $"&state={request.State}";
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return Redirect(errorRedirectUri);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "OAuth授权时发生错误");
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                // 错误重定向
							 | 
						||
| 
								 | 
							
								                var errorRedirectUri = $"{request.RedirectUri}?error=server_error";
							 | 
						||
| 
								 | 
							
								                if (!string.IsNullOrEmpty(request.State))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    errorRedirectUri += $"&state={request.State}";
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return Redirect(errorRedirectUri);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// OAuth令牌端点
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpPost("token")]
							 | 
						||
| 
								 | 
							
								        [Microsoft.AspNetCore.Authorization.AllowAnonymous]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> ExchangeToken([FromForm] OAuthTokenRequestDto request)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _logger.LogInformation("OAuth令牌端点被调用");
							 | 
						||
| 
								 | 
							
								            
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogInformation("OAuth令牌交换请求: GrantType={GrantType}, ClientId={ClientId}, Username={Username}", 
							 | 
						||
| 
								 | 
							
								                    request.GrantType, request.ClientId, request.Username);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (request.GrantType == "authorization_code")
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var result = await _oauthService.ExchangeCodeForTokenAsync(request);
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    if (result.Success)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        return Ok(result);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    return BadRequest(result);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else if (request.GrantType == "refresh_token")
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var result = await _oauthService.RefreshTokenAsync(request);
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    if (result.Success)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        return Ok(result);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    return BadRequest(result);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else if (request.GrantType == "password")
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    _logger.LogInformation("处理密码授权类型登录请求");
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    // 创建OAuth登录请求
							 | 
						||
| 
								 | 
							
								                    var loginDto = new OAuthLoginDto
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        UsernameOrEmail = request.Username,
							 | 
						||
| 
								 | 
							
								                        Password = request.Password,
							 | 
						||
| 
								 | 
							
								                        ClientId = request.ClientId,
							 | 
						||
| 
								 | 
							
								                        ClientSecret = request.ClientSecret,
							 | 
						||
| 
								 | 
							
								                        Scope = request.Scope
							 | 
						||
| 
								 | 
							
								                    };
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    var result = await _oauthService.LoginAsync(loginDto);
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    if (result.Success)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        _logger.LogInformation("密码授权类型登录成功");
							 | 
						||
| 
								 | 
							
								                        return Ok(result);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    _logger.LogWarning("密码授权类型登录失败: {Message}", result.Message);
							 | 
						||
| 
								 | 
							
								                    return BadRequest(result);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    _logger.LogWarning("不支持的授权类型: {GrantType}", request.GrantType);
							 | 
						||
| 
								 | 
							
								                    return BadRequest(new { message = "不支持的授权类型" });
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "OAuth令牌交换时发生错误");
							 | 
						||
| 
								 | 
							
								                return StatusCode(500, new { message = "服务器内部错误" });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 撤销令牌
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpPost("revoke")]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> RevokeToken([FromForm] string token, [FromForm] string token_type_hint = "access_token")
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var result = await _oauthService.RevokeTokenAsync(token);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return Ok(new { message = "令牌已撤销" });
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return BadRequest(result);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "撤销令牌时发生错误");
							 | 
						||
| 
								 | 
							
								                return StatusCode(500, new { message = "服务器内部错误" });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 验证令牌
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        [HttpPost("introspect")]
							 | 
						||
| 
								 | 
							
								        public async Task<IActionResult> IntrospectToken([FromForm] string token)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            try
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var result = await _oauthService.ValidateTokenAsync(token);
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var accessToken = await _oauthService.GetAccessTokenAsync(token);
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                    if (accessToken != null)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        return Ok(new
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            active = true,
							 | 
						||
| 
								 | 
							
								                            scope = accessToken.Scopes,
							 | 
						||
| 
								 | 
							
								                            client_id = accessToken.Client.ClientId,
							 | 
						||
| 
								 | 
							
								                            username = accessToken.User.Email,
							 | 
						||
| 
								 | 
							
								                            exp = ((DateTimeOffset)accessToken.ExpiresAt).ToUnixTimeSeconds(),
							 | 
						||
| 
								 | 
							
								                            iat = ((DateTimeOffset)accessToken.CreatedAt).ToUnixTimeSeconds()
							 | 
						||
| 
								 | 
							
								                        });
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                return Ok(new { active = false });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (Exception ex)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _logger.LogError(ex, "验证令牌时发生错误");
							 | 
						||
| 
								 | 
							
								                return StatusCode(500, new { message = "服务器内部错误" });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |