节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
3.54 KiB
Stardust
using System;
using Microsoft.AspNetCore.Mvc;
using NewLife;
using NewLife.Remoting;
using NewLife.Remoting.Extensions;
using NewLife.Remoting.Services;
using Stardust.Data;
using Stardust.Data.Gateway;
using Stardust.Server.Services;

namespace Stardust.Server.Controllers;

/// <summary>网关控制器。为 StarGateway 实例提供配置查询接口(安全V-10:需应用身份,防公网拓扑泄露)</summary>
[Route("[controller]")]
public class GatewayController : ControllerBase
{
    #region 属性
    private readonly GatewayService _gatewayService;
    private readonly AppTokenService _appTokenService;
    private readonly ITokenService _tokenService;
    private readonly StarServerSetting _setting;
    #endregion

    #region 构造
    /// <summary>实例化网关控制器</summary>
    public GatewayController(GatewayService gatewayService, AppTokenService appTokenService, ITokenService tokenService, StarServerSetting setting)
    {
        _gatewayService = gatewayService;
        _appTokenService = appTokenService;
        _tokenService = tokenService;
        _setting = setting;
    }
    #endregion

    #region 接口
    /// <summary>获取完整的网关配置(路由表 + 集群 + 节点 + 证书)</summary>
    /// <returns>网关配置</returns>
    [HttpGet("config")]
    public GatewayConfig GetConfig(String appId = null, String secret = null, String clientId = null, String token = null)
    {
        if (!Valid(appId, secret, token))
        {
            Response.StatusCode = 401;
            return null;
        }
        return _gatewayService.GetAllConfig();
    }

    /// <summary>获取指定集群的配置</summary>
    /// <param name="clusterId">集群编号</param>
    /// <returns>集群配置</returns>
    [HttpGet("cluster")]
    public GatewayClusterInfo GetCluster(Int32 clusterId, String appId = null, String secret = null, String clientId = null, String token = null)
    {
        if (!Valid(appId, secret, token))
        {
            Response.StatusCode = 401;
            return null;
        }
        return _gatewayService.GetClusterInfo(clusterId);
    }

    /// <summary>获取所有启用的路由</summary>
    /// <returns>路由列表</returns>
    [HttpGet("routes")]
    public IList<Data.Gateway.GatewayRoute> GetRoutes(String appId = null, String secret = null, String clientId = null, String token = null)
    {
        if (!Valid(appId, secret, token))
        {
            Response.StatusCode = 401;
            return null;
        }
        return _gatewayService.GetAllRoutes();
    }
    #endregion

    #region 辅助
    /// <summary>校验调用方。优先应用令牌;否则应用标识+密钥(StarGateway 走此路径)。失败返回 false(调用方回退本地配置)</summary>
    private Boolean Valid(String appId, String secret, String token)
    {
        try
        {
            // 令牌优先
            if (!token.IsNullOrEmpty())
            {
                var (jwt, ex) = _tokenService.DecodeToken(token);
                if (ex != null) return false;

                var app = App.FindByName(jwt?.Subject);
                if (app == null || !app.Enable || app.Secret.IsNullOrEmpty()) return false;
                return true;
            }

            // 应用标识+密钥(StarGateway 已按此形态调用)
            var ip = HttpContext.GetUserHost();
            _appTokenService.Authorize(appId, secret, _setting.AppAutoRegister, ip);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
    #endregion
}