定义登录验证protobuf

修改proto/user/user.proto

  1. syntax = "proto3";
  2. package micro.service.user;
  3. option go_package = "proto/user";
  4. service UserService {
  5. rpc Pagination(PaginationRequest) returns(PaginationResponse){}
  6. rpc Get(GetRequest) returns(UserResponse){}
  7. rpc Create(CreateRequest) returns(UserResponse){}
  8. rpc Update(UpdateRequest) returns(UserResponse){}
  9. rpc Delete(DeleteRequest) returns(UserResponse){}
  10. rpc Auth(AuthRequest) returns(TokenResponse){}
  11. rpc ValidateToken(TokenRequest) returns(TokenResponse){}
  12. }
  13. message User{
  14. uint64 id = 1;
  15. string name = 3;
  16. string email = 4;
  17. string real_name = 6;
  18. string avatar = 7;
  19. string create_at = 9;
  20. string update_at = 10;
  21. }
  22. //UserResponse 单个用户响应
  23. message UserResponse{
  24. User user = 1;
  25. }
  26. //PaginationResponse 用户分页数据响应
  27. message PaginationResponse{
  28. repeated User users = 1;
  29. uint64 total = 2;
  30. }
  31. //PaginationRequest 用户分页请求
  32. message PaginationRequest{
  33. uint64 page = 1;
  34. uint32 perPage = 2;
  35. }
  36. //GetRequest 获取单个用户请求
  37. message GetRequest{
  38. uint64 id = 1;
  39. }
  40. //CreateRequest 创建用户请求
  41. message CreateRequest{
  42. string name = 1;
  43. string password = 2;
  44. string email = 3;
  45. string real_name = 4;
  46. string avatar = 5;
  47. }
  48. //UpdateRequest 更新用户请求
  49. message UpdateRequest{
  50. uint64 id = 1;
  51. string name = 2;
  52. string email = 3;
  53. string real_name = 4;
  54. string avatar = 6;
  55. }
  56. //DeleteRequest 删除用户请求
  57. message DeleteRequest{
  58. uint64 id = 1;
  59. }
  60. //AuthRequest 登录请求
  61. message AuthRequest{
  62. string email = 1;
  63. string password = 2;
  64. }
  65. //TokenRequest token验证接口
  66. message TokenRequest{
  67. string token = 1;
  68. }
  69. //TokenResponse token响应接口
  70. message TokenResponse{
  71. string token = 1;
  72. bool valid = 2;
  73. }

生成protobuf代码

  1. make proto

引用jwt编写获取token业务

获取jwt生成包

  1. go get -u github.com/dgrijalva/jwt-go

创建service目录

  1. mkdir service
  2. touch service/token.go
  1. package service
  2. import (
  3. "github.com/869413421/micro-service/user/pkg/model"
  4. "github.com/869413421/micro-service/user/pkg/repo"
  5. "github.com/dgrijalva/jwt-go"
  6. "time"
  7. )
  8. var (
  9. key = []byte("microServiceUserTokenKeySecret")
  10. )
  11. // CustomClaims jwt认证对象
  12. type CustomClaims struct {
  13. User *model.User
  14. jwt.StandardClaims
  15. }
  16. // Authble jwt实现接口
  17. type Authble interface {
  18. Decode(token string) (*CustomClaims, error)
  19. Encode(user *model.User) (string, error)
  20. }
  21. // TokenService token业务对象
  22. type TokenService struct {
  23. Repo repo.UserRepositoryInterface
  24. }
  25. // NewTokenService token业务初始化
  26. func NewTokenService() Authble {
  27. return &TokenService{Repo: repo.NewUserRepository()}
  28. }
  29. // Decode 将token字符串转换为token对象
  30. func (srv *TokenService) Decode(tokenString string) (*CustomClaims, error) {
  31. // Parse the token
  32. token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
  33. return key, nil
  34. })
  35. // Validate the token and return the custom claims
  36. if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
  37. return claims, nil
  38. } else {
  39. return nil, err
  40. }
  41. }
  42. // Encode 将token对象串转换为token字符串
  43. func (srv *TokenService) Encode(user *model.User) (string, error) {
  44. expireToken := time.Now().Add(time.Hour * 72).Unix()
  45. // Create the Claims
  46. claims := CustomClaims{
  47. user,
  48. jwt.StandardClaims{
  49. ExpiresAt: expireToken,
  50. Issuer: "micro.service.user",
  51. },
  52. }
  53. // Create token
  54. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  55. // Sign token and return
  56. return token.SignedString(key)
  57. }

实现服务处理器

为UserServiceHandler增加token业务层

  1. ...
  2. //UserServiceHandler 用户服务处理器
  3. type UserServiceHandler struct {
  4. UserRepo repo.UserRepositoryInterface
  5. TokenService service.Authble
  6. }
  7. // NewUserServiceHandler 用户服务初始化
  8. func NewUserServiceHandler() *UserServiceHandler {
  9. return &UserServiceHandler{
  10. UserRepo: repo.NewUserRepository(),
  11. TokenService: service.NewTokenService(),
  12. }
  13. }
  14. ...

实现登录验证token接口

UserServiceHandler加上实现方法

  1. ...
  2. // Auth 认证获取token
  3. func (srv UserServiceHandler) Auth(ctx context.Context, req *pb.AuthRequest, rsp *pb.TokenResponse) error {
  4. // 1.根据邮箱回去用户
  5. log.Println("Logging in with:", req.Email, req.Password)
  6. user, err := srv.UserRepo.GetByEmail(req.Email)
  7. if err != nil && err != gorm.ErrRecordNotFound {
  8. return err
  9. }
  10. if err == gorm.ErrRecordNotFound {
  11. return errors.NotFound("User.Auth.GetByEmail.Error", "user not found ,check you password or email")
  12. }
  13. // 2.检验用户密码
  14. err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password))
  15. if err != nil {
  16. return errors.Unauthorized("User.Auth.CheckPassword.Error", err.Error())
  17. }
  18. // 3.生成token
  19. token, err := srv.TokenService.Encode(user)
  20. if err != nil {
  21. return err
  22. }
  23. // 4.返回token字符串
  24. rsp.Token = token
  25. return nil
  26. }
  27. // ValidateToken 验证token
  28. func (srv *UserServiceHandler) ValidateToken(ctx context.Context, req *pb.TokenRequest, rsp *pb.TokenResponse) error {
  29. // 1.将token字符串转换为token对象
  30. claims, err := srv.TokenService.Decode(req.Token)
  31. if err != nil {
  32. return err
  33. }
  34. // 2.判断转换是否成功
  35. if claims.User.ID == 0 {
  36. return errors.BadRequest("User.ValidateToken.Error", "user invalid")
  37. }
  38. // 3.返回验证状态
  39. rsp.Token = req.Token
  40. rsp.Valid = true
  41. return nil
  42. }
  43. ...

编译代码准备测试

  1. make build

打开micro工具测试接口

http://127.0.0.1:8082/client