登录与注册

dev
truthhun 2 years ago
parent 45a62a0773
commit 10bf9cdf13

@ -15,26 +15,25 @@ option java_package = "api.v1";
message User {
int64 id = 1;
string username = 2;
string password = 3;
string nickname = 4;
string mobile = 5;
string email = 6;
string address = 7;
string signature = 8;
string last_login_ip = 9;
string register_ip = 10;
int32 doc_count = 11;
int32 follow_count = 12;
int32 fans_count = 13;
int32 favorite_count = 14;
int32 comment_count = 15;
int32 status = 16;
string avatar = 17;
string identity = 18;
string realname = 19;
google.protobuf.Timestamp login_at = 20 [ (gogoproto.stdtime) = true ];
google.protobuf.Timestamp created_at = 21 [ (gogoproto.stdtime) = true ];
google.protobuf.Timestamp updated_at = 22 [ (gogoproto.stdtime) = true ];
string nickname = 3;
string mobile = 4;
string email = 5;
string address = 6;
string signature = 7;
string last_login_ip = 8;
string register_ip = 9;
int32 doc_count = 10;
int32 follow_count = 11;
int32 fans_count = 12;
int32 favorite_count = 13;
int32 comment_count = 14;
int32 status = 15;
string avatar = 16;
string identity = 17;
string realname = 18;
google.protobuf.Timestamp login_at = 19 [ (gogoproto.stdtime) = true ];
google.protobuf.Timestamp created_at = 20 [ (gogoproto.stdtime) = true ];
google.protobuf.Timestamp updated_at = 21 [ (gogoproto.stdtime) = true ];
}
message RegisterAndLoginRequest {
@ -46,18 +45,20 @@ message RegisterAndLoginRequest {
}
message GetUserCaptchaRequest {
string type = 1; // registerlogincommentfind_passwordupload
string type =
1; // registerlogincommentfind_passwordupload
}
message LoginReply { string token = 1; }
message LoginReply {
string token = 1;
User user = 2;
}
message UpdateUserRequest {
int64 id = 1;
string name = 2;
}
message UpdateUserReply { User user = 1; }
message DeleteUserRequest { repeated int64 id = 1; }
message GetUserRequest { int64 id = 1; }
@ -120,6 +121,15 @@ service UserAPI {
};
}
// ID
// 穿ID
rpc UpdateUser(User) returns (User) {
option (google.api.http) = {
put : '/api/v1/user/password',
body : '*',
};
}
//
rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {

@ -2,9 +2,11 @@ package biz
import (
"context"
"time"
pb "moredoc/api/v1"
"moredoc/model"
"moredoc/util"
"moredoc/util/validate"
"moredoc/util/captcha"
@ -12,6 +14,7 @@ import (
"github.com/alexandrevicenzi/unchained"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
@ -61,7 +64,10 @@ func (s *UserAPIService) Register(ctx context.Context, req *pb.RegisterAndLoginR
return nil, status.Errorf(codes.AlreadyExists, "用户名已存在")
}
user := &model.User{Username: req.Username, Password: req.Password}
user := &model.User{Username: req.Username, Password: req.Password, RegisterIp: ip}
if p, ok := peer.FromContext(ctx); ok {
user.RegisterIp = p.Addr.String()
}
if err = s.dbModel.CreateUser(user); err != nil {
s.logger.Error("CreateUser", zap.Error(err))
return nil, status.Errorf(codes.Internal, err.Error())
@ -73,6 +79,7 @@ func (s *UserAPIService) Register(ctx context.Context, req *pb.RegisterAndLoginR
// Login 用户登录
// TODO: 1. 判断是否启用了验证码,如果启用了验证码,则需要进行验证码验证
func (s *UserAPIService) Login(ctx context.Context, req *pb.RegisterAndLoginRequest) (*pb.LoginReply, error) {
errValidate := validate.ValidateStruct(req, s.getValidFieldMap())
if errValidate != nil {
return nil, status.Errorf(codes.InvalidArgument, errValidate.Error())
@ -84,7 +91,7 @@ func (s *UserAPIService) Login(ctx context.Context, req *pb.RegisterAndLoginRequ
return nil, status.Errorf(codes.InvalidArgument, "验证码错误")
}
user, err := s.dbModel.GetUserByUsername(req.Username, "id", "password")
user, err := s.dbModel.GetUserByUsername(req.Username)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
@ -97,13 +104,28 @@ func (s *UserAPIService) Login(ctx context.Context, req *pb.RegisterAndLoginRequ
return nil, status.Errorf(codes.Internal, err.Error())
}
return &pb.LoginReply{Token: token}, nil
pbUser := &pb.User{}
util.CopyStruct(&user, pbUser)
ip := ""
if p, ok := peer.FromContext(ctx); ok {
ip = p.Addr.String()
}
if e := s.dbModel.UpdateUser(&model.User{Id: user.Id, LoginAt: time.Now(), LastLoginIp: ip}, "login_at", "last_login_ip"); e != nil {
s.logger.Error("UpdateUser", zap.Error(e))
}
return &pb.LoginReply{Token: token, User: pbUser}, nil
}
func (s *UserAPIService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
return &pb.User{}, nil
}
func (s *UserAPIService) UpdateUser(ctx context.Context, req *pb.User) (*pb.User, error) {
return &pb.User{}, nil
}
func (s *UserAPIService) UpdateUserPassword(ctx context.Context, req *pb.UpdateUserRequest) (*pb.User, error) {
return &pb.User{}, nil
}

@ -21,8 +21,8 @@ type User struct {
Email string `form:"email" json:"email,omitempty" gorm:"column:email;type:varchar(64);size:64;index:email;comment:联系邮箱;"`
Address string `form:"address" json:"address,omitempty" gorm:"column:address;type:varchar(255);size:255;comment:联系地址;"`
Signature string `form:"signature" json:"signature,omitempty" gorm:"column:signature;type:varchar(255);size:255;comment:签名;"`
LastLoginIp string `form:"last_login_ip" json:"last_login_ip,omitempty" gorm:"column:last_login_ip;type:varchar(16);size:16;comment:最后登录 ip 地址;"`
RegisterIp string `form:"register_ip" json:"register_ip,omitempty" gorm:"column:register_ip;type:varchar(16);size:16;comment:注册ip;"`
LastLoginIp string `form:"last_login_ip" json:"last_login_ip,omitempty" gorm:"column:last_login_ip;type:varchar(32);size:32;comment:最后登录 ip 地址;"`
RegisterIp string `form:"register_ip" json:"register_ip,omitempty" gorm:"column:register_ip;type:varchar(32);size:32;comment:注册ip;"`
DocCount int `form:"doc_count" json:"doc_count,omitempty" gorm:"column:doc_count;type:int(10) unsigned;default:0;comment:上传的文档数;"`
FollowCount int `form:"follow_count" json:"follow_count,omitempty" gorm:"column:follow_count;type:int(10) unsigned;default:0;comment:关注数;"`
FansCount int `form:"fans_count" json:"fans_count,omitempty" gorm:"column:fans_count;type:int(10) unsigned;default:0;comment:粉丝数;"`

@ -46,14 +46,18 @@ func GenerateCaptcha(captchaType string) (id, b64s string, err error) {
Width: width,
NoiseCount: 0,
}
case "chinese":
driver = &base64Captcha.DriverChinese{
Height: height,
Width: width,
Source: sourceChinese,
Length: 4, // 4个字符
Fonts: []string{"wqy-microhei.ttc"},
}
// case "chinese":
// driver = base64Captcha.NewDriverChinese(
// height,
// width,
// 0,
// 0,
// 4,
// sourceChinese,
// nil,
// nil,
// []string{"wqy-microhei.ttc"},
// ).ConvertFonts()
default:
driver = &base64Captcha.DriverDigit{
Height: height,

@ -1 +1,9 @@
package util
import jsoniter "github.com/json-iterator/go"
// CopyStruct 拷贝。注意只能拷贝相同类型的结构体且结构体中有json标签
func CopyStruct(srcPtr, dstPtr interface{}) {
bytes, _ := jsoniter.Marshal(srcPtr)
jsoniter.Unmarshal(bytes, dstPtr)
}

@ -32,6 +32,14 @@ export const updateUserPassword = (data) => {
})
}
export const updateUser = (data) => {
return service({
url: '/api/v1/user/password',
method: 'put',
data,
})
}
export const deleteUser = (params) => {
return service({
url: '/api/v1/user',

@ -4,6 +4,8 @@ body{
background-color: #fff;
}
.pointer{cursor: pointer;}
.btn-block{
width: 100%;
}
@ -53,7 +55,7 @@ body{
.page-login{
.el-card{
width: 400px;
width: 450px;
max-width: 100%;
margin: 20vh auto;
}

@ -15,6 +15,30 @@
@keydown.native.enter="execLogin"
></el-input>
</el-form-item>
<el-form-item v-if="captcha.enable" label="验证码">
<div v-if="captcha.type == 'audio'">
<el-row :gutter="15">
<el-col :span="20">
<audio controls="controls" :src="captcha.captcha"></audio>
</el-col>
<el-col :span="4">
<el-tooltip placement="top" content="刷新语音验证码">
<el-button
icon="el-icon-refresh"
class="btn-audio-refresh"
@click="loadCaptcha"
></el-button>
</el-tooltip>
</el-col>
</el-row>
</div>
<div v-else>
<el-tooltip placement="right" content="点击可刷新验证码">
<img :src="captcha.captcha" class="pointer" @click="loadCaptcha" />
</el-tooltip>
</div>
<el-input v-model="user.captcha" placeholder="请输入验证码"></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@ -29,7 +53,7 @@
</template>
<script>
import { mapActions } from 'vuex'
import {getUserCaptcha} from '~/api/user'
import { getUserCaptcha } from '~/api/user'
export default {
name: 'FormLogin',
data() {
@ -37,18 +61,38 @@ export default {
user: {
username: '',
password: '',
captcha: '',
captcha_id: '',
},
captcha: {
enable: false,
},
}
},
async created(){
const res = await getUserCaptcha({type:'login'})
console.log(res)
created() {
this.loadCaptcha()
},
methods: {
...mapActions('user', ['Login']),
async execLogin() {
await this.Login(this.user)
},
async loadCaptcha() {
const res = await getUserCaptcha({ type: 'login', t: Date.now() })
if (res.data.enable) {
//
this.user = {
...this.user,
captcha_id: res.data.id,
}
this.captcha = res.data
}
},
},
}
</script>
<style scoped>
.btn-audio-refresh {
vertical-align: -webkit-baseline-middle;
}
</style>

@ -2,7 +2,7 @@
<div class="page-login">
<el-card shadow="never">
<div slot="header" class="clearfix">
<span>用户登录</span>
<span>管理员登录</span>
</div>
<form-login></form-login>
</el-card>
@ -16,7 +16,7 @@ export default {
middleware: ['auth'],
head() {
return {
title: `用户登录 - MOREDOC · 魔刀文库`,
title: `管理员登录 - MOREDOC · 魔刀文库`,
}
},
}

@ -1,5 +1,5 @@
import { Message } from 'element-ui'
import { login, getUser, setUserProfile } from '~/api/user'
import { login, getUser, updateUser } from '~/api/user'
export const user = {
namespaced: true,
state: {
@ -36,8 +36,8 @@ export const user = {
}
return res
},
async setUserProfile({ commit }, profile) {
const res = await setUserProfile(profile)
async updateUser({ commit }, profile) {
const res = await updateUser(profile)
if (res.status === 200) {
commit('setUser', res.data.data)
Message({
@ -55,19 +55,15 @@ export const user = {
async Login({ commit }, loginInfo) {
const res = await login(loginInfo)
if (res.status === 200) {
commit('setUser', res.data.data.user)
commit('setToken', res.data.data.token)
Message({
type: 'success',
message: '登录成功',
})
location.reload()
commit('setUser', res.data.user)
commit('setToken', res.data.token)
} else {
Message({
type: 'error',
message: res.data.message || '登录失败',
})
}
return res
},
Logout({ commit }) {
commit('logout')

Loading…
Cancel
Save