Browse Source

login

master
linquan 1 month ago
parent
commit
5676691210
  1. 2
      api/v1/system/sys_email.go
  2. 34
      api/v1/system/sys_login.go
  3. 12
      email.go
  4. 7
      internal/consts/consts.go
  5. 154
      internal/controller/sys_login.go
  6. 37
      internal/service/aliyunSms.go
  7. 68
      internal/service/email.go
  8. 62
      internal/service/sys_user.go

2
api/v1/system/sys_email.go

@ -4,7 +4,7 @@ import "github.com/gogf/gf/v2/frame/g"
type SendEmailReq struct {
g.Meta `path:"/sendEmail" tags:"email" method:"post" summary:"邮件"`
Phone string `p:"userName"`
Code string `p:"code"`
}
type SendEmailRes struct {

34
api/v1/system/sys_login.go

@ -28,12 +28,18 @@ type UserLoginRes struct {
Permissions []string `json:"permissions"`
}
type UserLoginOutReq struct {
g.Meta `path:"/loginOut" tags:"登录" method:"delete" summary:"退出登录"`
Authorization string `p:"Authorization" in:"header" dc:"Bearer {{token}}"`
}
type UserLoginOutRes struct {
}
type UserLoginMobileReq struct {
g.Meta `path:"/loginMobile" tags:"登录" method:"post" summary:"用户登录"`
g.Meta `path:"/loginMobile" tags:"登录" method:"post" summary:"用户手机登录"`
Phone string `p:"userName" v:"required#手机号不能为空"`
Code string `p:"code" v:"required#验证码不能为空"`
//VerifyCode string `p:"verifyCode" v:"required#验证码不能为空"`
//VerifyKey string `p:"verifyKey"`
}
type UserLoginMobileRes struct {
@ -52,10 +58,24 @@ type MobileCodeReq struct {
type MobileCodeRes struct {
}
type UserLoginOutReq struct {
g.Meta `path:"/loginOut" tags:"登录" method:"delete" summary:"退出登录"`
Authorization string `p:"Authorization" in:"header" dc:"Bearer {{token}}"`
type UserLoginEmailReq struct {
g.Meta `path:"/loginEmail" tags:"登录" method:"post" summary:"用户邮箱登录"`
Email string `p:"userName" v:"required#邮箱不能为空"`
Code string `p:"code" v:"required#验证码不能为空"`
}
type UserLoginOutRes struct {
type UserLoginEmailRes struct {
g.Meta `mime:"application/json"`
UserInfo *model2.LoginUserRes `json:"userInfo"`
Token string `json:"token"`
MenuList []*model2.UserMenus `json:"menuList"`
Permissions []string `json:"permissions"`
}
type EmailCodeReq struct {
g.Meta `path:"/emailCode" tags:"登录" method:"post" summary:"邮箱验证码"`
Email string `p:"userName" v:"required#邮箱不能为空"`
}
type EmailCodeRes struct {
}

12
email.go

@ -9,13 +9,13 @@ import (
func main() {
e := email.NewEmail()
e.From = "lin <13950405063@163.com>"
e.From = "lin <linquan13950405063@163.com>"
e.To = []string{"349589071@qq.com"}
e.Cc = []string{"linquan13950405063@163.com"}
e.Subject = "Awesome web"
e.Text = []byte("Text Body is, of course, supported!")
err := e.Send("smtp.163.com:25", smtp.PlainAuth("", "linquan13950405063@163.com", "lin_quan120", "smtp.163.com"))
e.Bcc = []string{"linquan13950405063@163.com"}
e.Subject = "【桃源记2】验证码"
e.HTML = []byte("这是桃源记2后台登录的验证码 <br><br>验证码: 713379 <br><br>请在10分钟内使用。")
err := e.Send("smtp.163.com:25", smtp.PlainAuth("", "linquan13950405063@163.com", "YGefKDbTiwMRW3nM", "smtp.163.com"))
if err != nil {
log.Fatal(err)
log.Print(err)
}
}

7
internal/consts/consts.go

@ -97,10 +97,3 @@ const CHARSETDef = "0123456789abcdefghijklmnopqrstuvwxyz"
const CHARSETSpecial = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
const DEFAULT_HOST = "127.0.0.1"
const TEMPLATE_CODE_BIND = "SMS_205408382" // 短信模板id
const TEMPLATE_CODE_PASSWORD = "SMS_205440227"
const CODE_SIGN_NAME = "桃源记" // 签名
const CODE_ACCESS_KEY_ID = "LTAI4GBDHSn2itPipVdt8rXu" // accessKeyId
const CODE_ACCESS_SECRET = "KOzOtz0dGyqZLpSg0QXRkGrBroRMjL" // accessSecret
const CODE_REGION_ID = "cn-hangzhou"

154
internal/controller/sys_login.go

@ -113,6 +113,13 @@ func (c *loginController) Login(ctx context.Context, req *system.UserLoginReq) (
return
}
// LoginOut 退出登录
func (c *loginController) LoginOut(ctx context.Context, req *system.UserLoginOutReq) (res *system.UserLoginOutRes, err error) {
err = service.SysGfToken().RemoveToken(ctx, service.SysGfToken().GetRequestToken(g.RequestFromCtx(ctx)))
return
}
// LoginMobile 手机登录
func (c *loginController) LoginMobile(ctx context.Context, req *system.UserLoginMobileReq) (res *system.UserLoginMobileRes, err error) {
var (
user *model.LoginUserRes
@ -183,11 +190,9 @@ func (c *loginController) LoginMobile(ctx context.Context, req *system.UserLogin
// MobileCode 获取验证码
func (c *loginController) MobileCode(ctx context.Context, req *system.MobileCodeReq) (res *system.MobileCodeRes, err error) {
log.Println("MobileCode: ", gjson.MustEncodeString(req))
user, err := service.User().GetUserByMobile(ctx, req.Phone)
liberr.ErrIsNil(ctx, err)
liberr.ValueIsNil(user, "手机验证码错误")
ip := libUtils.GetClientIp(ctx)
userAgent := libUtils.GetUserAgent(ctx)
user, err := service.User().GetUserByMobile(ctx, req.Phone)
if err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
@ -200,6 +205,7 @@ func (c *loginController) MobileCode(ctx context.Context, req *system.MobileCode
})
return
}
liberr.ValueIsNil(user, "手机验证码错误")
code, err := service.User().GetCodeByMobile(ctx, req.Phone)
if err != nil {
// 保存登录失败的日志信息
@ -213,24 +219,134 @@ func (c *loginController) MobileCode(ctx context.Context, req *system.MobileCode
})
return
}
//err = service.AliYunSms().Main([]string{req.Phone, code})
//if err != nil {
// // 保存登录失败的日志信息
// service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
// Status: 0,
// Username: req.Phone,
// Ip: ip,
// UserAgent: userAgent,
// Msg: err.Error(),
// Module: "系统后台",
// })
// return
//}
err = service.AliYunSms().Main([]string{req.Phone, code})
if err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
Status: 0,
Username: req.Phone,
Ip: ip,
UserAgent: userAgent,
Msg: err.Error(),
Module: "系统后台",
})
return
}
return
}
// LoginOut 退出登录
func (c *loginController) LoginOut(ctx context.Context, req *system.UserLoginOutReq) (res *system.UserLoginOutRes, err error) {
err = service.SysGfToken().RemoveToken(ctx, service.SysGfToken().GetRequestToken(g.RequestFromCtx(ctx)))
// LoginEmail 邮件登录
func (c *loginController) LoginEmail(ctx context.Context, req *system.UserLoginEmailReq) (res *system.UserLoginEmailRes, err error) {
var (
user *model.LoginUserRes
token string
permissions []string
menuList []*model.UserMenus
)
//判断验证码是否正确
debug := gmode.IsDevelop()
if !debug {
//if !service.Captcha().VerifyString(req.VerifyKey, req.VerifyCode) {
// err = gerror.New("验证码输入错误")
// return
//}
}
ip := libUtils.GetClientIp(ctx)
userAgent := libUtils.GetUserAgent(ctx)
user, err = service.User().GetAdminUserByEmail(ctx, req)
if err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
Status: 0,
Username: req.Email,
Ip: ip,
UserAgent: userAgent,
Msg: err.Error(),
Module: "系统后台",
})
return
}
err = service.User().UpdateLoginInfo(ctx, user.Id, ip)
if err != nil {
return
}
// 报存登录成功的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
Status: 1,
Username: req.Email,
Ip: ip,
UserAgent: userAgent,
Msg: "登录成功",
Module: "系统后台",
})
key := gconv.String(user.Id) + "-" + gmd5.MustEncryptString(user.UserName) + gmd5.MustEncryptString(user.UserPassword)
if g.Cfg().MustGet(ctx, "gfToken.multiLogin").Bool() {
key = gconv.String(user.Id) + "-" + gmd5.MustEncryptString(user.UserName) + gmd5.MustEncryptString(user.UserPassword+ip+userAgent)
}
user.UserPassword = ""
token, err = service.SysGfToken().GenerateToken(ctx, key, user)
if err != nil {
return
}
//获取用户菜单数据
menuList, permissions, err = service.User().GetAdminRules(ctx, user.Id)
if err != nil {
return
}
res = &system.UserLoginEmailRes{
UserInfo: user,
Token: token,
MenuList: menuList,
Permissions: permissions,
}
return
}
// EmailCode 获取验证码
func (c *loginController) EmailCode(ctx context.Context, req *system.EmailCodeReq) (res *system.EmailCodeRes, err error) {
log.Println("EmailCode: ", gjson.MustEncodeString(req))
ip := libUtils.GetClientIp(ctx)
userAgent := libUtils.GetUserAgent(ctx)
user, err := service.User().GetUserByEmail(ctx, req.Email)
if err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
Status: 0,
Username: req.Email,
Ip: ip,
UserAgent: userAgent,
Msg: err.Error(),
Module: "系统后台",
})
return
}
liberr.ValueIsNil(user, "验证码错误")
code, err := service.User().GetCodeByEmail(ctx, req.Email)
if err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
Status: 0,
Username: req.Email + "_" + code,
Ip: ip,
UserAgent: userAgent,
Msg: err.Error(),
Module: "系统后台",
})
return
}
err = service.Email().SendEmail(req.Email, code)
if err != nil {
// 保存登录失败的日志信息
service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{
Status: 0,
Username: req.Email,
Ip: ip,
UserAgent: userAgent,
Msg: err.Error(),
Module: "系统后台",
})
return
}
return
}

37
internal/service/aliyunSms.go

@ -10,9 +10,10 @@ import (
"github.com/alibabacloud-go/tea/tea"
credential "github.com/aliyun/credentials-go/credentials"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"log"
"strings"
"tyj_admin/internal/consts"
)
type IAliYunSms interface {
@ -29,6 +30,30 @@ func AliYunSms() IAliYunSms {
return &aliYunSmsService
}
type AliyunSms struct {
AccessKeyId string
AccessSecret string
RegionId string
CodeSignName string
TemplateCode string
}
var (
smsConfig AliyunSms
)
func init() {
//加载游戏相关配置
ctx := gctx.New()
smsConfig.AccessKeyId = g.Cfg().MustGet(ctx, "game.sms.accessKeyId").String()
smsConfig.AccessSecret = g.Cfg().MustGet(ctx, "game.sms.accessSecret").String()
smsConfig.RegionId = g.Cfg().MustGet(ctx, "game.sms.regionId").String()
smsConfig.CodeSignName = g.Cfg().MustGet(ctx, "game.sms.codeSignName").String()
smsConfig.TemplateCode = g.Cfg().MustGet(ctx, "game.sms.templateCodePass").String()
}
/*
Description:
@ -46,10 +71,10 @@ func (a *aliYunSmsServiceTmpl) CreateClient() (_result *dysmsapi20170525.Client,
config := &openapi.Config{
Credential: credential,
// 您的AccessKey ID
AccessKeyId: tea.String(consts.CODE_ACCESS_KEY_ID),
AccessKeyId: tea.String(smsConfig.AccessKeyId),
// 您的AccessKey Secret
AccessKeySecret: tea.String(consts.CODE_ACCESS_SECRET),
RegionId: tea.String(consts.CODE_REGION_ID),
AccessKeySecret: tea.String(smsConfig.AccessSecret),
RegionId: tea.String(smsConfig.RegionId),
}
// Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
@ -74,8 +99,8 @@ func (a *aliYunSmsServiceTmpl) Main(args []string) (_err error) {
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
PhoneNumbers: tea.String(args[0]),
SignName: tea.String(consts.CODE_SIGN_NAME),
TemplateCode: tea.String(consts.TEMPLATE_CODE_PASSWORD),
SignName: tea.String(smsConfig.CodeSignName),
TemplateCode: tea.String(smsConfig.TemplateCode),
TemplateParam: tea.String(gjson.MustEncodeString(map[string]string{"code": args[1]})),
}

68
internal/service/email.go

@ -1,15 +1,18 @@
package service
import (
"context"
"crypto/tls"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/jordan-wright/email"
"log"
"net/smtp"
"tyj_admin/api/v1/system"
"strings"
)
type IEmail interface {
SendEmail(ctx context.Context, req *system.SendEmailReq) (res *system.SendEmailRes, err error)
SendEmail(emailAddr, code string) (err error)
}
type emailServiceTmpl struct {
@ -21,6 +24,34 @@ func Email() IEmail {
return &emailService
}
type EmailTmpl struct {
From string
EmailAddr string
Password string
Smtp string
Port string
Subject string
HTML string
}
var (
emailConfig EmailTmpl
)
func init() {
//加载游戏相关配置
ctx := gctx.New()
emailConfig.From = g.Cfg().MustGet(ctx, "game.email.from").String()
emailConfig.EmailAddr = g.Cfg().MustGet(ctx, "game.email.emailAddr").String()
emailConfig.Smtp = g.Cfg().MustGet(ctx, "game.email.smtp").String()
emailConfig.Password = g.Cfg().MustGet(ctx, "game.email.password").String()
emailConfig.Port = g.Cfg().MustGet(ctx, "game.email.port").String()
emailConfig.Subject = g.Cfg().MustGet(ctx, "game.email.subject").String()
emailConfig.HTML = g.Cfg().MustGet(ctx, "game.email.html").String()
}
/*
* Description:
*
@ -28,15 +59,30 @@ func Email() IEmail {
* @return Client
* @throws Exception
*/
func (a *emailServiceTmpl) SendEmail(ctx context.Context, req *system.SendEmailReq) (res *system.SendEmailRes, err error) {
func (a *emailServiceTmpl) SendEmail(emailAddr, code string) (err error) {
e := email.NewEmail()
e.From = "lin <13950405063@163.com>"
e.To = []string{"349589071@qq.com"}
e.Subject = "Awesome web"
e.Text = []byte("Text Body is, of course, supported!")
err = e.Send("smtp.163.com:25", smtp.PlainAuth("", "linquan13950405063@163.com", "lin_quan120", "smtp.163.com"))
if err != nil {
log.Fatal(err)
e.From = emailConfig.From
e.To = []string{emailAddr}
e.Bcc = []string{emailConfig.EmailAddr}
e.Subject = emailConfig.Subject
e.HTML = []byte(strings.Replace(emailConfig.HTML, "CODE", code, -1))
log.Println("SendEmail: ", gjson.MustEncodeString(emailConfig))
auth := smtp.PlainAuth("", emailConfig.EmailAddr, emailConfig.Password, emailConfig.Smtp)
if emailConfig.Port == "25" {
err = e.Send(emailConfig.Smtp+":"+emailConfig.Port, auth)
if err != nil {
log.Println("SendEmail: Send:", err)
}
} else {
tc := &tls.Config{
ServerName: emailConfig.Smtp,
InsecureSkipVerify: true,
}
err = e.SendWithTLS(emailConfig.Smtp+":"+emailConfig.Port, auth, tc)
if err != nil {
log.Println("SendEmail: SendWithTLS: ", err)
}
}
return
}

62
internal/service/sys_user.go

@ -35,6 +35,7 @@ import (
type IUser interface {
GetAdminUserByUsernamePassword(ctx context.Context, req *system.UserLoginReq) (user *model2.LoginUserRes, err error)
GetAdminUserByPhone(ctx context.Context, req *system.UserLoginMobileReq) (user *model2.LoginUserRes, err error)
GetAdminUserByEmail(ctx context.Context, req *system.UserLoginEmailReq) (user *model2.LoginUserRes, err error)
LoginLog(ctx context.Context, params *model2.LoginLogParams)
UpdateLoginInfo(ctx context.Context, id uint64, ip string) (err error)
NotCheckAuthAdminIds(ctx context.Context) *gset.Set
@ -49,7 +50,9 @@ type IUser interface {
Delete(ctx context.Context, ids []int) (err error)
GetUserByUsername(ctx context.Context, userName string) (user *model2.LoginUserRes, err error)
GetUserByMobile(ctx context.Context, mobile string) (user *model2.LoginUserRes, err error)
GetUserByEmail(ctx context.Context, email string) (user *model2.LoginUserRes, err error)
GetCodeByMobile(ctx context.Context, mobile string) (code string, err error)
GetCodeByEmail(ctx context.Context, email string) (code string, err error)
}
type userImpl struct {
@ -127,6 +130,29 @@ func (s *userImpl) GetAdminUserByPhone(ctx context.Context, req *system.UserLogi
return
}
func (s *userImpl) GetAdminUserByEmail(ctx context.Context, req *system.UserLoginEmailReq) (user *model2.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
user, err = s.GetUserByEmail(ctx, req.Email)
liberr.ErrIsNil(ctx, err)
liberr.ValueIsNil(user, "验证码错误")
log.Printf("GetAdminUserByPhone >>> Email:%s", req.Email)
//验证密码
model, ok := codes[req.Email]
log.Printf("GetAdminUserByPhone >>> Email:%s, time %s ", req.Email, fmt.Sprint(model.Time.Unix())+"--"+fmt.Sprint(gtime.Now().Unix()))
if !ok || model.Time.Unix()+600 < gtime.Now().Unix() {
liberr.ErrIsNil(ctx, gerror.New("验证码错误"))
}
if libUtils.EncryptPassword(req.Code+fmt.Sprint(model.Time.Unix()), user.UserSalt) != model.Password {
liberr.ErrIsNil(ctx, gerror.New("验证码错误"))
}
//账号状态
if user.UserStatus == 0 {
liberr.ErrIsNil(ctx, gerror.New("账号已被冻结"))
}
})
return
}
// GetUserByUsername 通过用户名获取用户信息
func (s *userImpl) GetUserByUsername(ctx context.Context, userName string) (user *model2.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
@ -147,6 +173,16 @@ func (s *userImpl) GetUserByMobile(ctx context.Context, mobile string) (user *mo
return
}
// GetUserByEmail 通过邮箱获取用户信息
func (s *userImpl) GetUserByEmail(ctx context.Context, email string) (user *model2.LoginUserRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
user = &model2.LoginUserRes{}
err = dao.SysUser.Ctx(ctx).Fields(user).Where(dao.SysUser.Columns().UserEmail, email).Scan(user)
liberr.ErrIsNil(ctx, err, "验证码错误")
})
return
}
// GetCodeByMobile 通过手机号获取Code
func (s *userImpl) GetCodeByMobile(ctx context.Context, mobile string) (code string, err error) {
err = g.Try(ctx, func(ctx context.Context) {
@ -173,6 +209,32 @@ func (s *userImpl) GetCodeByMobile(ctx context.Context, mobile string) (code str
return
}
// GetCodeByEmail 通过邮箱获取Code
func (s *userImpl) GetCodeByEmail(ctx context.Context, email string) (code string, err error) {
err = g.Try(ctx, func(ctx context.Context) {
user, err := s.GetUserByEmail(ctx, email)
liberr.ErrIsNil(ctx, err)
liberr.ValueIsNil(user, "验证码错误")
log.Printf("GetCodeByMobile >>> email:%s", email)
code = utils.GenerateRandomString(6)
//验证密码
time := gtime.Now()
password := libUtils.EncryptPassword(code+fmt.Sprint(time.Unix()), user.UserSalt)
codes[email] = CodeModel{
Code: code,
Time: time,
Password: password,
}
log.Printf("GetCodeByMobile >>> email:%s", gjson.MustEncodeString(codes[email]))
//账号状态
if user.UserStatus == 0 {
liberr.ErrIsNil(ctx, gerror.New("账号已被冻结"))
}
})
return
}
// LoginLog 记录登录日志
func (s *userImpl) LoginLog(ctx context.Context, params *model2.LoginLogParams) {
ua := user_agent.New(params.UserAgent)

Loading…
Cancel
Save