Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 17eff99

Browse files
committed
新注册用户、发布内容太多、太频繁,发布内容需要验证码
1 parent ce45a00 commit 17eff99

File tree

21 files changed

+299
-60
lines changed

21 files changed

+299
-60
lines changed

src/http/controller/account.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (self AccountController) Register(ctx echo.Context) error {
6161
data := map[string]interface{}{
6262
"username": username,
6363
"email": ctx.FormValue("email"),
64-
"captchaId": captcha.NewLen(4),
64+
"captchaId": captcha.NewLen(util.CaptchaLen),
6565
}
6666

6767
disallowUsers := config.ConfigFile.MustValueArray("account", "disallow_user", ",")
@@ -72,9 +72,11 @@ func (self AccountController) Register(ctx echo.Context) error {
7272
}
7373
}
7474

75+
captchaId := ctx.FormValue("captchaid")
7576
// 校验验证码
76-
if !captcha.VerifyString(ctx.FormValue("captchaid"), ctx.FormValue("captchaSolution")) {
77-
data["error"] = "验证码错误"
77+
if !captcha.VerifyString(captchaId, ctx.FormValue("captchaSolution")) {
78+
data["error"] = "验证码错误,记得刷新验证码"
79+
util.SetCaptcha(captchaId)
7880
return render(ctx, registerTpl, data)
7981
}
8082

src/http/controller/article.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"logic"
1212
"net/http"
1313
"strings"
14+
"util"
1415

16+
"github.com/dchest/captcha"
1517
"github.com/labstack/echo"
1618
"github.com/polaris1119/echoutils"
1719
"github.com/polaris1119/goutils"
@@ -38,7 +40,7 @@ func (self ArticleController) RegisterRoute(g *echo.Group) {
3840

3941
g.Get("/articles/:id", self.Detail)
4042

41-
g.Match([]string{"GET", "POST"}, "/articles/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice())
43+
g.Match([]string{"GET", "POST"}, "/articles/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice(), middleware.CheckCaptcha())
4244
g.Match([]string{"GET", "POST"}, "/articles/modify", self.Modify, middleware.NeedLogin(), middleware.Sensivite())
4345
}
4446

@@ -146,16 +148,21 @@ func (ArticleController) Detail(ctx echo.Context) error {
146148

147149
// Create 发布新文章
148150
func (ArticleController) Create(ctx echo.Context) error {
151+
me := ctx.Get("user").(*model.Me)
152+
149153
title := ctx.FormValue("title")
150154
if title == "" || ctx.Request().Method() != "POST" {
151-
return render(ctx, "articles/new.html", map[string]interface{}{"activeArticles": "active"})
155+
data := map[string]interface{}{"activeArticles": "active"}
156+
if logic.NeedCaptcha(me) {
157+
data["captchaId"] = captcha.NewLen(util.CaptchaLen)
158+
}
159+
return render(ctx, "articles/new.html", data)
152160
}
153161

154162
if ctx.FormValue("content") == "" {
155163
return fail(ctx, 1, "内容不能为空")
156164
}
157165

158-
me := ctx.Get("user").(*model.Me)
159166
id, err := logic.DefaultArticle.Publish(echoutils.WrapEchoContext(ctx), me, ctx.FormParams())
160167
if err != nil {
161168
return fail(ctx, 2, "内部服务错误")

src/http/controller/project.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import (
1010
"http/middleware"
1111
"logic"
1212
"net/http"
13+
"util"
1314

15+
"github.com/dchest/captcha"
1416
"github.com/labstack/echo"
1517
"github.com/polaris1119/goutils"
1618

@@ -31,7 +33,7 @@ type ProjectController struct{}
3133
// 注册路由
3234
func (self ProjectController) RegisterRoute(g *echo.Group) {
3335
g.GET("/projects", self.ReadList)
34-
g.Match([]string{"GET", "POST"}, "/project/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice())
36+
g.Match([]string{"GET", "POST"}, "/project/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice(), middleware.CheckCaptcha())
3537
g.Match([]string{"GET", "POST"}, "/project/modify", self.Modify, middleware.NeedLogin(), middleware.Sensivite())
3638
g.GET("/p/:uri", self.Detail)
3739
g.GET("/project/uri", self.CheckExist)
@@ -71,15 +73,22 @@ func (ProjectController) ReadList(ctx echo.Context) error {
7173

7274
// Create 新建项目
7375
func (ProjectController) Create(ctx echo.Context) error {
76+
me := ctx.Get("user").(*model.Me)
77+
7478
name := ctx.FormValue("name")
7579
// 请求新建项目页面
7680
if name == "" || ctx.Request().Method() != "POST" {
7781
project := &model.OpenProject{}
78-
return render(ctx, "projects/new.html", map[string]interface{}{"project": project, "activeProjects": "active"})
82+
83+
data := map[string]interface{}{"project": project, "activeProjects": "active"}
84+
if logic.NeedCaptcha(me) {
85+
data["captchaId"] = captcha.NewLen(util.CaptchaLen)
86+
}
87+
88+
return render(ctx, "projects/new.html", data)
7989
}
8090

81-
user := ctx.Get("user").(*model.Me)
82-
err := logic.DefaultProject.Publish(ctx, user, ctx.FormParams())
91+
err := logic.DefaultProject.Publish(ctx, me, ctx.FormParams())
8392
if err != nil {
8493
return fail(ctx, 1, "内部服务错误!")
8594
}

src/http/controller/resource.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"http/middleware"
1212
"logic"
1313
"net/http"
14+
"util"
1415

16+
"github.com/dchest/captcha"
1517
"github.com/labstack/echo"
1618
"github.com/polaris1119/goutils"
1719

@@ -33,7 +35,7 @@ func (self ResourceController) RegisterRoute(g *echo.Group) {
3335
g.GET("/resources", self.ReadList)
3436
g.GET("/resources/cat/:catid", self.ReadCatResources)
3537
g.GET("/resources/:id", self.Detail)
36-
g.Match([]string{"GET", "POST"}, "/resources/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice())
38+
g.Match([]string{"GET", "POST"}, "/resources/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice(), middleware.CheckCaptcha())
3739
g.Match([]string{"GET", "POST"}, "/resources/modify", self.Modify, middleware.NeedLogin(), middleware.Sensivite())
3840
}
3941

@@ -96,10 +98,16 @@ func (ResourceController) Detail(ctx echo.Context) error {
9698

9799
// Create 发布新资源
98100
func (ResourceController) Create(ctx echo.Context) error {
101+
me := ctx.Get("user").(*model.Me)
102+
99103
title := ctx.FormValue("title")
100104
// 请求新建资源页面
101105
if title == "" || ctx.Request().Method() != "POST" {
102-
return render(ctx, "resources/new.html", map[string]interface{}{"activeResources": "active", "categories": logic.AllCategory})
106+
data := map[string]interface{}{"activeResources": "active", "categories": logic.AllCategory}
107+
if logic.NeedCaptcha(me) {
108+
data["captchaId"] = captcha.NewLen(util.CaptchaLen)
109+
}
110+
return render(ctx, "resources/new.html", data)
103111
}
104112

105113
errMsg := ""
@@ -117,7 +125,6 @@ func (ResourceController) Create(ctx echo.Context) error {
117125
return fail(ctx, 1, errMsg)
118126
}
119127

120-
me := ctx.Get("user").(*model.Me)
121128
err := logic.DefaultResource.Publish(ctx, me, ctx.FormParams())
122129
if err != nil {
123130
return fail(ctx, 2, "内部服务错误,请稍候再试!")

src/http/controller/topic.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import (
1313
"model"
1414
"net/http"
1515
"strconv"
16+
"util"
1617

1718
. "http"
1819

20+
"github.com/dchest/captcha"
1921
"github.com/labstack/echo"
2022
"github.com/polaris1119/goutils"
2123
)
@@ -39,7 +41,7 @@ func (self TopicController) RegisterRoute(g *echo.Group) {
3941
g.GET("/go/:node", self.GoNodeTopics)
4042
g.GET("/nodes", self.Nodes)
4143

42-
g.Match([]string{"GET", "POST"}, "/topics/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice())
44+
g.Match([]string{"GET", "POST"}, "/topics/new", self.Create, middleware.NeedLogin(), middleware.Sensivite(), middleware.BalanceCheck(), middleware.PublishNotice(), middleware.CheckCaptcha())
4345
g.Match([]string{"GET", "POST"}, "/topics/modify", self.Modify, middleware.NeedLogin(), middleware.Sensivite())
4446

4547
g.POST("/topics/set_top", self.SetTop, middleware.NeedLogin())
@@ -184,6 +186,8 @@ func (TopicController) Detail(ctx echo.Context) error {
184186
func (TopicController) Create(ctx echo.Context) error {
185187
nid := goutils.MustInt(ctx.FormValue("nid"))
186188

189+
me := ctx.Get("user").(*model.Me)
190+
187191
title := ctx.FormValue("title")
188192
// 请求新建主题页面
189193
if title == "" || ctx.Request().Method() != "POST" {
@@ -194,6 +198,11 @@ func (TopicController) Create(ctx echo.Context) error {
194198
"nid": nid,
195199
"tab_list": hotNodes,
196200
}
201+
202+
if logic.NeedCaptcha(me) {
203+
data["captchaId"] = captcha.NewLen(util.CaptchaLen)
204+
}
205+
197206
hadRecommend := false
198207
if len(logic.AllRecommendNodes) > 0 {
199208
hadRecommend = true
@@ -212,10 +221,9 @@ func (TopicController) Create(ctx echo.Context) error {
212221
return fail(ctx, 1, "没有选择节点!")
213222
}
214223

215-
me := ctx.Get("user").(*model.Me)
216224
tid, err := logic.DefaultTopic.Publish(ctx, me, ctx.FormParams())
217225
if err != nil {
218-
return fail(ctx, 1, "内部服务错误:"+err.Error())
226+
return fail(ctx, 3, "内部服务错误:"+err.Error())
219227
}
220228

221229
return success(ctx, map[string]interface{}{"tid": tid})

src/http/middleware/captcha.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2016 The StudyGolang Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
// http://studygolang.com
5+
// Author: polaris [email protected]
6+
7+
package middleware
8+
9+
import (
10+
"logic"
11+
"model"
12+
"net/http"
13+
"util"
14+
15+
"github.com/dchest/captcha"
16+
"github.com/labstack/echo"
17+
)
18+
19+
// CheckCaptcha 用于 echo 框架校验发布验证码
20+
func CheckCaptcha() echo.MiddlewareFunc {
21+
return func(next echo.HandlerFunc) echo.HandlerFunc {
22+
return func(ctx echo.Context) error {
23+
24+
curUser := ctx.Get("user").(*model.Me)
25+
26+
if ctx.Request().Method() == "POST" {
27+
if logic.NeedCaptcha(curUser) {
28+
captchaId := ctx.FormValue("captchaid")
29+
if !captcha.VerifyString(captchaId, ctx.FormValue("captchaSolution")) {
30+
util.SetCaptcha(captchaId)
31+
return ctx.String(http.StatusOK, `{"ok":0,"error":"验证码错误,记得刷新验证码!"}`)
32+
}
33+
}
34+
}
35+
36+
if err := next(ctx); err != nil {
37+
return err
38+
}
39+
40+
return nil
41+
}
42+
}
43+
}

src/logic/common.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ import (
1212
"model"
1313
"os"
1414
"regexp"
15+
"strconv"
1516
"time"
1617
"util"
1718

1819
"github.com/gorilla/schema"
20+
"github.com/polaris1119/goutils"
1921
"github.com/polaris1119/logger"
22+
"github.com/polaris1119/nosql"
23+
"github.com/polaris1119/times"
2024
"golang.org/x/net/context"
2125
)
2226

@@ -66,7 +70,7 @@ func CanEdit(me *model.Me, curModel interface{}) bool {
6670
return false
6771
}
6872

69-
canEditTime := time.Duration(UserSetting["can_edit_time"]) * time.Second
73+
canEditTime := time.Duration(UserSetting[model.KeyCanEditTime]) * time.Second
7074
switch entity := curModel.(type) {
7175
case *model.Topic:
7276
if me.Uid != entity.Uid && me.IsAdmin && roleCanEdit(model.TopicAdmin, me) {
@@ -206,6 +210,60 @@ func CanPublish(dauAuth, objtype int) bool {
206210
}
207211
}
208212

213+
// NeedCaptcha 是否需要验证码:
214+
// - 新客注册后一段时间内需要
215+
// - 发布内容太频繁(一天次数太多、间隔太快)
216+
func NeedCaptcha(user *model.Me) bool {
217+
// 注册后 30 分钟内发布需要验证码
218+
if user.CreatedAt.Add(30 * time.Minute).After(time.Now()) {
219+
return true
220+
}
221+
222+
// 发布内容是否太频繁
223+
redis := nosql.NewRedisFromPool()
224+
defer redis.Close()
225+
226+
publishTimes := redis.GET(getPublishTimesKey(user.Uid))
227+
if goutils.MustInt(publishTimes) > UserSetting[model.KeyPublishTimes] {
228+
return true
229+
}
230+
231+
lastTimestampStr := redis.GET(getLastPublishTimeKey(user.Uid))
232+
lastTimestamp := goutils.MustInt64(lastTimestampStr)
233+
if time.Now().Unix()-lastTimestamp < int64(UserSetting[model.KeyPublishInterval]) {
234+
return true
235+
}
236+
237+
return false
238+
}
239+
240+
// incrPublishTimes 增加用户发布次数
241+
func incrPublishTimes(uid int) {
242+
redis := nosql.NewRedisFromPool()
243+
defer redis.Close()
244+
245+
key := getPublishTimesKey(uid)
246+
redis.INCR(key)
247+
redis.EXPIRE(key, 86401)
248+
}
249+
250+
// recordLastPubishTime 记录用户上次发布时间
251+
func recordLastPubishTime(uid int) {
252+
redis := nosql.NewRedisFromPool()
253+
defer redis.Close()
254+
255+
key := getLastPublishTimeKey(uid)
256+
redis.SET(key, time.Now().Unix(), 86400)
257+
}
258+
259+
func getPublishTimesKey(uid int) string {
260+
return "publish:times:user:" + strconv.Itoa(uid) + ":date:" + times.Format("Ymd")
261+
}
262+
263+
func getLastPublishTimeKey(uid int) string {
264+
return "last:publish:time:user:" + strconv.Itoa(uid)
265+
}
266+
209267
func website() string {
210268
host := "http://"
211269
if WebsiteSetting.OnlyHttps {

src/logic/observer.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ func (*TodayActiveObserver) Update(action string, uid, objtype, objid int) {
145145
switch action {
146146
case actionPublish:
147147
weight = 20
148+
// 记录当天发布次数和上次发布时时间
149+
incrPublishTimes(uid)
150+
recordLastPubishTime(uid)
148151
case actionModify:
149152
weight = 2
150153
case actionComment:

src/logic/uploader.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ func (this *UploaderLogic) uploadLocalFile(localFile, key string) (err error) {
8989

9090
var ret io.PutRet
9191
var extra = &io.PutExtra{
92-
// Params: params,
93-
// MimeType: mieType,
94-
// Crc32: crc32,
95-
// CheckCrc: CheckCrc,
92+
// Params: params,
93+
// MimeType: mieType,
94+
// Crc32: crc32,
95+
// CheckCrc: CheckCrc,
9696
}
9797

9898
// ret 变量用于存取返回的信息,详情见 io.PutRet
@@ -119,10 +119,10 @@ func (this *UploaderLogic) uploadMemoryFile(r gio.Reader, key string, size int)
119119

120120
var ret io.PutRet
121121
var extra = &io.PutExtra{
122-
// Params: params,
123-
// MimeType: mieType,
124-
// Crc32: crc32,
125-
// CheckCrc: CheckCrc,
122+
// Params: params,
123+
// MimeType: mieType,
124+
// Crc32: crc32,
125+
// CheckCrc: CheckCrc,
126126
}
127127

128128
// ret 变量用于存取返回的信息,详情见 io.PutRet

0 commit comments

Comments
 (0)