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