短信服务(三):如何在公司内部为短信服务提供安全和成本的保障?(适合刷KPI)
一、为什么要在公司内部提到短信服务的安全性?
如果你在一个大公司,那么类似于短信这种资源,是需要考虑安全和成本控制的。比如说利用审批流程来 申请一个 tpl(模板),里面要求业务方对自己的用量进行评估。
而后要考虑:只有特定的组才能使用这个 tpl。这个 tpl 的容量不能超过一个数。比如说总共就是 一个月十万条 ,多了就要额外申请,以达成成本控制的目标。
【笔者去年在广州某中厂实习,其短信服务平台部分要求集团内部各业务方提供 1. QPS最大值 2. 每月用量。如下图】
二、实现思路
那怎么做到某个 tpl(或者说 接口 / 资源) 只能被申请的业务方使用?
使用 token 。
而且是内部调用,可以直接使用简单的 静态 token(如果是外部调用,就参考腾讯云短信服务怎么鉴权的 doge )(如果是动态 token ,就得设计成类似 login 接口那种 token 机制了,复杂没必要)。
即业务方申请一个 tpl
,而后你颁发一个 token
给它,要求它调用你的接口的时候,带上这个 token
。
2.1 两种设计方案
第一种:在 Send 方法里面加上一个 token 参数(属于破坏性修改,不使用该方法)
第二种:直接用 token 参数替换掉 tpl 参数。所需的各种数据,从 token 中解密出来(只需替换一个参数,可通过加装饰器实现,使用该方法可行)
我们用第二种。当业务方申请的时候,给业务方 一个 JWT token
,里面包含了一些跟业务方有关的信息。
三、代码
(0)代码目录结构:
(1)装饰器代码
package auth
import (
"context"
"github.com/golang-jwt/jwt/v5"
"refactor-webook/webook/internal/service/sms"
)
// SmsService 装饰器
type SmsService struct {
svc sms.Service
key string
}
func NewSmsService(svc sms.Service) *SmsService {
return &SmsService{
svc: svc,
key: "oIft1b5qZjyLcc0zZo2UrUx5rk3KE0LvZKv73fw502oXd6vfYu1OAQvbSel8whv1",
}
}
func (s *SmsService) Send(ctx context.Context, jwtTpl string, args []string, numbers ...string) error {
var tc TplClaims
_, err := jwt.ParseWithClaims(jwtTpl, &tc, func(token *jwt.Token) (interface{}, error) {
return s.key, nil
})
if err != nil {
return err
}
return s.svc.Send(ctx, tc.Tpl, args, numbers...)
}
type TplClaims struct {
jwt.RegisteredClaims
Tpl string
// 可再添加额外字段
}
(2)调用该装饰器代码
package ioc
import (
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tencentSMS "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111"
"os"
"refactor-webook/webook/internal/service/localsms"
"refactor-webook/webook/internal/service/sms"
"refactor-webook/webook/internal/service/sms/tencent"
)
func InitSMSService() sms.Service {
// 调用内部鉴权的装饰器
return auth.NewSmsService(initTencentSMSService())
}
func initTencentSMSService() sms.Service {
secretId, ok := os.LookupEnv("SMS_SECRET_ID")
if !ok {
panic("找不到腾讯 SMS 的 secret id")
}
secretKey, ok := os.LookupEnv("SMS_SECRET_KEY")
if !ok {
panic("找不到腾讯 SMS 的 secret key")
}
c, err := tencentSMS.NewClient(
common.NewCredential(secretId, secretKey),
"ap-nanjing",
profile.NewClientProfile(),
)
if err != nil {
panic(err)
}
return tencent.NewService(c, "1400842696", "傻瓜科技")
}
转载自:https://juejin.cn/post/7387968084789542946