mirror of
https://github.com/songquanpeng/message-pusher.git
synced 2025-09-26 20:21:22 +08:00
feat: support channel level auth
This commit is contained in:
@@ -214,6 +214,7 @@ proxy_send_timeout 300s;
|
||||
15. `tencent_alarm`:通过腾讯云监控告警进行推送,仅支持 `description` 字段。
|
||||
16. `none`:仅保存到数据库,不做推送。
|
||||
5. `token`:如果你在后台设置了推送 token,则此项必填。另外可以通过设置 HTTP `Authorization` 头部设置此项。
|
||||
* 注意令牌有两种,一种是全局鉴权令牌,一种是通道维度的令牌,前者可以鉴权任何通道,后者只能鉴权指定通道。
|
||||
6. `url`:选填,如果不填则系统自动为消息生成 URL,其内容为消息详情。
|
||||
7. `to`:选填,推送给指定用户,如果不填则默认推送给自己,受限于具体的消息推送方式,有些推送方式不支持此项。
|
||||
1. `@all`:推送给所有用户。
|
||||
|
@@ -135,6 +135,7 @@ func AddChannel(c *gin.Context) {
|
||||
URL: channel_.URL,
|
||||
Other: channel_.Other,
|
||||
CreatedTime: common.GetTimestamp(),
|
||||
Token: channel_.Token,
|
||||
}
|
||||
err = cleanChannel.Insert()
|
||||
if err != nil {
|
||||
@@ -206,6 +207,7 @@ func UpdateChannel(c *gin.Context) {
|
||||
cleanChannel.AccountId = channel_.AccountId
|
||||
cleanChannel.URL = channel_.URL
|
||||
cleanChannel.Other = channel_.Other
|
||||
cleanChannel.Token = channel_.Token
|
||||
}
|
||||
err = cleanChannel.Update()
|
||||
if err != nil {
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"message-pusher/model"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -46,7 +47,7 @@ func GetPushMessage(c *gin.Context) {
|
||||
|
||||
func PostPushMessage(c *gin.Context) {
|
||||
var message model.Message
|
||||
if c.Request.Header.Get("Content-Type") == "application/json" {
|
||||
if strings.Contains(strings.ToLower(c.Request.Header.Get("Content-Type")), "application/json") {
|
||||
// Looks like the user is using JSON
|
||||
message = model.Message{}
|
||||
err := json.NewDecoder(c.Request.Body).Decode(&message)
|
||||
@@ -110,28 +111,26 @@ func pushMessageHelper(c *gin.Context, message *model.Message) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if user.Token != "" && user.Token != " " {
|
||||
if message.Token == "" {
|
||||
message.Token = c.Request.Header.Get("Authorization")
|
||||
if message.Token == "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": false,
|
||||
"message": "token 为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
if user.Token != message.Token {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": false,
|
||||
"message": "无效的 token",
|
||||
})
|
||||
return
|
||||
}
|
||||
if message.Token == "" {
|
||||
message.Token = strings.TrimPrefix(c.Request.Header.Get("Authorization"), "Bearer ")
|
||||
}
|
||||
processMessage(c, message, &user)
|
||||
}
|
||||
|
||||
func authMessage(messageToken string, userToken string, channelToken *string) bool {
|
||||
if userToken != "" {
|
||||
if messageToken == userToken {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if channelToken != nil && *channelToken != "" {
|
||||
if messageToken != *channelToken {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func processMessage(c *gin.Context, message *model.Message, user *model.User) {
|
||||
if message.Title == "" {
|
||||
message.Title = common.SystemName
|
||||
@@ -150,6 +149,20 @@ func processMessage(c *gin.Context, message *model.Message, user *model.User) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if !authMessage(message.Token, user.Token, channel_.Token) {
|
||||
if message.Token == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"success": false,
|
||||
"message": "通道维度或用户维度设置了鉴权令牌,需要提供鉴权令牌",
|
||||
})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"success": false,
|
||||
"message": "无效的 token",
|
||||
})
|
||||
return
|
||||
}
|
||||
err = saveAndSendMessage(user, message, channel_)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
|
@@ -25,18 +25,19 @@ const (
|
||||
)
|
||||
|
||||
type Channel struct {
|
||||
Id int `json:"id"`
|
||||
Type string `json:"type" gorm:"type:varchar(32)"`
|
||||
UserId int `json:"user_id" gorm:"uniqueIndex:name_user_id;index"`
|
||||
Name string `json:"name" gorm:"type:varchar(32);uniqueIndex:name_user_id"`
|
||||
Description string `json:"description"`
|
||||
Status int `json:"status" gorm:"default:1"` // enabled, disabled
|
||||
Secret string `json:"secret" gorm:"index"`
|
||||
AppId string `json:"app_id"`
|
||||
AccountId string `json:"account_id"`
|
||||
URL string `json:"url" gorm:"column:url"`
|
||||
Other string `json:"other"`
|
||||
CreatedTime int64 `json:"created_time" gorm:"bigint"`
|
||||
Id int `json:"id"`
|
||||
Type string `json:"type" gorm:"type:varchar(32)"`
|
||||
UserId int `json:"user_id" gorm:"uniqueIndex:name_user_id;index"`
|
||||
Name string `json:"name" gorm:"type:varchar(32);uniqueIndex:name_user_id"`
|
||||
Description string `json:"description"`
|
||||
Status int `json:"status" gorm:"default:1"` // enabled, disabled
|
||||
Secret string `json:"secret" gorm:"index"`
|
||||
AppId string `json:"app_id"`
|
||||
AccountId string `json:"account_id"`
|
||||
URL string `json:"url" gorm:"column:url"`
|
||||
Other string `json:"other"`
|
||||
CreatedTime int64 `json:"created_time" gorm:"bigint"`
|
||||
Token *string `json:"token" gorm:"token"`
|
||||
}
|
||||
|
||||
type BriefChannel struct {
|
||||
@@ -120,7 +121,7 @@ func (channel *Channel) UpdateStatus(status int) error {
|
||||
// Update Make sure your token's fields is completed, because this will update non-zero values
|
||||
func (channel *Channel) Update() error {
|
||||
var err error
|
||||
err = DB.Model(channel).Select("type", "name", "description", "secret", "app_id", "account_id", "url", "other", "status").Updates(channel).Error
|
||||
err = DB.Model(channel).Select("type", "name", "description", "secret", "app_id", "account_id", "url", "other", "status", "token").Updates(channel).Error
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Form, Grid, Header, Message } from 'semantic-ui-react';
|
||||
import { API, showError, showSuccess, testChannel } from '../helpers';
|
||||
import {
|
||||
API,
|
||||
generateToken,
|
||||
showError,
|
||||
showSuccess,
|
||||
testChannel,
|
||||
} from '../helpers';
|
||||
import { loadUser, loadUserChannels } from '../helpers/loader';
|
||||
|
||||
const PushSetting = () => {
|
||||
@@ -70,15 +76,25 @@ const PushSetting = () => {
|
||||
options={channels}
|
||||
value={user.channel}
|
||||
onChange={handleInputChange}
|
||||
width={6}
|
||||
width={5}
|
||||
/>
|
||||
<Form.Input
|
||||
label='全局鉴权令牌'
|
||||
placeholder='未设置渠道维度令牌时,会检查该令牌,如果该令牌也没有设置,则不检查'
|
||||
placeholder='优先级高于通道维度令牌,但为了安全期间建议使用通道维度的令牌'
|
||||
value={user.token}
|
||||
name='token'
|
||||
onChange={handleInputChange}
|
||||
width={10}
|
||||
width={9}
|
||||
action={{
|
||||
content: '随机生成',
|
||||
onClick: () => {
|
||||
console.log('generate token');
|
||||
setUser((inputs) => ({
|
||||
...inputs,
|
||||
token: generateToken(16),
|
||||
}));
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Button onClick={() => submit('general')} loading={loading}>
|
||||
|
Reference in New Issue
Block a user