actions.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package main
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "errors"
  6. "fmt"
  7. "math/rand"
  8. "net/http"
  9. "sparrow/pkg/models"
  10. "sparrow/pkg/rpcs"
  11. "sparrow/pkg/server"
  12. "sparrow/pkg/token"
  13. "strconv"
  14. "strings"
  15. "github.com/martini-contrib/render"
  16. )
  17. const (
  18. ErrOK = 0
  19. ErrSystemFault = 10001
  20. ErrDeviceNotFound = 10002
  21. ErrWrongSecret = 10003
  22. ErrProtocolNotSuported = 10004
  23. )
  24. func renderError(code int, err error) Common {
  25. result := Common{}
  26. result.Code = code
  27. result.Message = err.Error()
  28. server.Log.Error(err.Error())
  29. return result
  30. }
  31. // DeviceRegisterArgs device register args
  32. type DeviceRegisterArgs struct {
  33. ProductKey string `json:"product_key" binding:"required"`
  34. DeviceCode string `json:"device_code" binding:"required"`
  35. Version string `json:"version" binding:"required"`
  36. ModuleName string `json:"module" binding:"required"`
  37. }
  38. // DeviceAuthArgs device authentication args
  39. type DeviceAuthArgs struct {
  40. DeviceId int64 `json:"device_id" binding:"required"`
  41. DeviceSecret string `json:"device_secret" binding:"required"`
  42. Protocol string `json:"protocol" binding:"required"`
  43. }
  44. type AccessAuthArgs struct {
  45. UserName string `json:"username"`
  46. Password string `json:"password"`
  47. }
  48. type AccessAuthResp struct {
  49. Result string `json:"result"` // 可选 "allow" | "deny" | "ignore"
  50. IsSuperuser bool `json:"is_superuser"` // false
  51. }
  52. // RegisterDevice 设备激活
  53. func RegisterDevice(args DeviceRegisterArgs, r render.Render) {
  54. server.Log.Printf("ACTION RegisterDevice, args:: %v ", args)
  55. rpcargs := &rpcs.ArgsDeviceRegister{
  56. ProductKey: args.ProductKey,
  57. DeviceCode: args.DeviceCode,
  58. DeviceVersion: args.Version,
  59. ModuleName: args.ModuleName,
  60. }
  61. device := &models.Device{}
  62. err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.RegisterDevice", rpcargs, device)
  63. if err != nil {
  64. r.JSON(http.StatusOK, renderError(ErrSystemFault, err))
  65. return
  66. }
  67. server.Log.Infof("register device success: %v", device)
  68. result := DeviceRegisterResponse{}
  69. result.Data = DeviceRegisterData{
  70. DeviceId: int64(device.ID),
  71. DeviceSecret: device.DeviceSecret,
  72. DeviceKey: device.DeviceKey,
  73. DeviceIdentifier: device.DeviceIdentifier,
  74. }
  75. r.JSON(http.StatusOK, result)
  76. return
  77. }
  78. // DeviceAccessAuth emqx 设备接入认证
  79. func DeviceAccessAuth(args AccessAuthArgs, r render.Render) {
  80. server.Log.Printf("ACTION DeviceAccessAuth, args:: %v", args)
  81. result := AccessAuthResp{}
  82. deviceId, err := ClientIDToDeviceID(args.UserName)
  83. if err != nil {
  84. server.Log.Errorf("invalid Identify: %s", args.UserName)
  85. result.Result = "deny"
  86. r.JSON(http.StatusOK, result)
  87. return
  88. }
  89. device := &models.Device{}
  90. err = server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindDeviceById", deviceId, device)
  91. if err != nil {
  92. server.Log.Errorf("device not found %d", deviceId)
  93. result.Result = "deny"
  94. r.JSON(http.StatusOK, result)
  95. return
  96. }
  97. // parse token
  98. token, err := hex.DecodeString(args.Password)
  99. if err != nil {
  100. server.Log.Errorf("token format error : %v", err)
  101. result.Result = "deny"
  102. r.JSON(http.StatusOK, result)
  103. return
  104. }
  105. // validate token
  106. if err := validateToken(device.RecordId, token); err != nil {
  107. server.Log.Errorf("validate token error : %v", err)
  108. result.Result = "deny"
  109. r.JSON(http.StatusOK, result)
  110. return
  111. }
  112. result.Result = "allow"
  113. r.JSON(http.StatusOK, result)
  114. }
  115. func validateToken(deviceRecordId string, token []byte) error {
  116. args := rpcs.ArgsValidateDeviceAccessToken{
  117. Id: deviceRecordId,
  118. AccessToken: token,
  119. }
  120. reply := rpcs.ReplyValidateDeviceAccessToken{}
  121. err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.ValidateDeviceAccessToken", args, &reply)
  122. if err != nil {
  123. return err
  124. }
  125. return nil
  126. }
  127. // AuthDevice device auth
  128. func AuthDevice(args DeviceAuthArgs, r render.Render) {
  129. device := &models.Device{}
  130. arg := uint64(args.DeviceId)
  131. err := server.RPCCallByName(context.Background(), rpcs.RegistryServerName, "Registry.FindDeviceById", &arg, device)
  132. if err != nil {
  133. r.JSON(http.StatusOK, renderError(ErrDeviceNotFound, err))
  134. return
  135. }
  136. fmt.Printf(fmt.Sprintf("%s, %s", device.DeviceSecret, args.DeviceSecret))
  137. if device.DeviceSecret != args.DeviceSecret {
  138. // device secret is wrong.
  139. r.JSON(http.StatusOK, renderError(ErrWrongSecret, errors.New("wrong device secret.")))
  140. return
  141. }
  142. hepler := token.NewHelper(*confRedisHost, *confRedisPort, *confRedisDb)
  143. token, err := hepler.GenerateToken(device.RecordId)
  144. if err != nil {
  145. r.JSON(http.StatusOK, renderError(ErrSystemFault, err))
  146. return
  147. }
  148. var hosts []string
  149. switch args.Protocol {
  150. case "http":
  151. hosts, err = server.GetServerHosts(strings.ToUpper(args.Protocol)+"Access", "httphost")
  152. case "mqtt":
  153. hosts, err = server.GetServerHosts(strings.ToUpper(args.Protocol)+"Access", "tcphost")
  154. case "coap":
  155. hosts, err = server.GetServerHosts(strings.ToUpper(args.Protocol)+"Access", "udphost")
  156. case "mqttX": // TODO: 增加配置文件支持
  157. hosts = []string{
  158. "114.115.251.196:1883",
  159. }
  160. default:
  161. err = errors.New("unsuported protocol: " + args.Protocol)
  162. }
  163. if err != nil {
  164. r.JSON(http.StatusOK, renderError(ErrProtocolNotSuported, err))
  165. return
  166. }
  167. // just get a random host
  168. host := hosts[rand.Intn(len(hosts))]
  169. result := DeviceAuthResponse{}
  170. result.Data = DeviceAuthData{
  171. AccessToken: hex.EncodeToString(token),
  172. AccessAddr: host,
  173. }
  174. server.Log.Infof("auth device success: %v, token: %x, access: %v", device, token, host)
  175. r.JSON(http.StatusOK, result)
  176. return
  177. }
  178. func ClientIDToDeviceID(identify string) (uint64, error) {
  179. deviceId, err := strconv.ParseUint(identify, 16, 64)
  180. if err != nil {
  181. return uint64(0), err
  182. }
  183. return deviceId, nil
  184. }