login.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package admin
  2. import (
  3. "fmt"
  4. "github.com/gin-gonic/gin"
  5. "github.com/lejianwen/rustdesk-api/v2/global"
  6. "github.com/lejianwen/rustdesk-api/v2/http/controller/api"
  7. "github.com/lejianwen/rustdesk-api/v2/http/request/admin"
  8. apiReq "github.com/lejianwen/rustdesk-api/v2/http/request/api"
  9. "github.com/lejianwen/rustdesk-api/v2/http/response"
  10. adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
  11. "github.com/lejianwen/rustdesk-api/v2/model"
  12. "github.com/lejianwen/rustdesk-api/v2/service"
  13. )
  14. type Login struct {
  15. }
  16. // Login 登录
  17. // @Tags 登录
  18. // @Summary 登录
  19. // @Description 登录
  20. // @Accept json
  21. // @Produce json
  22. // @Param body body admin.Login true "登录信息"
  23. // @Success 200 {object} response.Response{data=adResp.LoginPayload}
  24. // @Failure 500 {object} response.Response
  25. // @Router /admin/login [post]
  26. // @Security token
  27. func (ct *Login) Login(c *gin.Context) {
  28. if global.Config.App.DisablePwdLogin {
  29. response.Fail(c, 101, response.TranslateMsg(c, "PwdLoginDisabled"))
  30. return
  31. }
  32. // 检查登录限制
  33. loginLimiter := global.LoginLimiter
  34. clientIp := c.ClientIP()
  35. _, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
  36. f := &admin.Login{}
  37. err := c.ShouldBindJSON(f)
  38. if err != nil {
  39. loginLimiter.RecordFailedAttempt(clientIp)
  40. global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
  41. response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
  42. return
  43. }
  44. errList := global.Validator.ValidStruct(c, f)
  45. if len(errList) > 0 {
  46. loginLimiter.RecordFailedAttempt(clientIp)
  47. global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
  48. response.Fail(c, 101, errList[0])
  49. return
  50. }
  51. // 检查是否需要验证码
  52. if needCaptcha {
  53. if f.CaptchaId == "" || f.Captcha == "" || !loginLimiter.VerifyCaptcha(f.CaptchaId, f.Captcha) {
  54. response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError"))
  55. return
  56. }
  57. }
  58. u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
  59. if u.Id == 0 {
  60. global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), clientIp))
  61. loginLimiter.RecordFailedAttempt(clientIp)
  62. if _, needCaptcha = loginLimiter.CheckSecurityStatus(clientIp); needCaptcha {
  63. response.Fail(c, 110, response.TranslateMsg(c, "UsernameOrPasswordError"))
  64. } else {
  65. response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
  66. }
  67. return
  68. }
  69. if !service.AllService.UserService.CheckUserEnable(u) {
  70. if needCaptcha {
  71. response.Fail(c, 110, response.TranslateMsg(c, "UserDisabled"))
  72. return
  73. }
  74. response.Fail(c, 101, response.TranslateMsg(c, "UserDisabled"))
  75. return
  76. }
  77. ut := service.AllService.UserService.Login(u, &model.LoginLog{
  78. UserId: u.Id,
  79. Client: model.LoginLogClientWebAdmin,
  80. Uuid: "", //must be empty
  81. Ip: clientIp,
  82. Type: model.LoginLogTypeAccount,
  83. Platform: f.Platform,
  84. })
  85. // 登录成功,清除登录限制
  86. loginLimiter.RemoveAttempts(clientIp)
  87. responseLoginSuccess(c, u, ut.Token)
  88. }
  89. func (ct *Login) Captcha(c *gin.Context) {
  90. loginLimiter := global.LoginLimiter
  91. clientIp := c.ClientIP()
  92. banned, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
  93. if banned {
  94. response.Fail(c, 101, response.TranslateMsg(c, "LoginBanned"))
  95. return
  96. }
  97. if !needCaptcha {
  98. response.Fail(c, 101, response.TranslateMsg(c, "NoCaptchaRequired"))
  99. return
  100. }
  101. err, captcha := loginLimiter.RequireCaptcha()
  102. if err != nil {
  103. response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError")+err.Error())
  104. return
  105. }
  106. err, b64 := loginLimiter.DrawCaptcha(captcha.Content)
  107. if err != nil {
  108. response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError")+err.Error())
  109. return
  110. }
  111. response.Success(c, gin.H{
  112. "captcha": gin.H{
  113. "id": captcha.Id,
  114. "b64": b64,
  115. },
  116. })
  117. }
  118. // Logout 登出
  119. // @Tags 登录
  120. // @Summary 登出
  121. // @Description 登出
  122. // @Accept json
  123. // @Produce json
  124. // @Success 200 {object} response.Response
  125. // @Failure 500 {object} response.Response
  126. // @Router /admin/logout [post]
  127. func (ct *Login) Logout(c *gin.Context) {
  128. u := service.AllService.UserService.CurUser(c)
  129. token, ok := c.Get("token")
  130. if ok {
  131. service.AllService.UserService.Logout(u, token.(string))
  132. }
  133. response.Success(c, nil)
  134. }
  135. // LoginOptions
  136. // @Tags 登录
  137. // @Summary 登录选项
  138. // @Description 登录选项
  139. // @Accept json
  140. // @Produce json
  141. // @Success 200 {object} []string
  142. // @Failure 500 {object} response.ErrorResponse
  143. // @Router /admin/login-options [post]
  144. func (ct *Login) LoginOptions(c *gin.Context) {
  145. loginLimiter := global.LoginLimiter
  146. clientIp := c.ClientIP()
  147. banned, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
  148. if banned {
  149. response.Fail(c, 101, response.TranslateMsg(c, "LoginBanned"))
  150. return
  151. }
  152. ops := service.AllService.OauthService.GetOauthProviders()
  153. response.Success(c, gin.H{
  154. "ops": ops,
  155. "register": global.Config.App.Register,
  156. "need_captcha": needCaptcha,
  157. })
  158. }
  159. // OidcAuth
  160. // @Tags Oauth
  161. // @Summary OidcAuth
  162. // @Description OidcAuth
  163. // @Accept json
  164. // @Produce json
  165. // @Router /admin/oidc/auth [post]
  166. func (ct *Login) OidcAuth(c *gin.Context) {
  167. // o := &api.Oauth{}
  168. // o.OidcAuth(c)
  169. f := &apiReq.OidcAuthRequest{}
  170. err := c.ShouldBindJSON(f)
  171. if err != nil {
  172. response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
  173. return
  174. }
  175. err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(c, f.Op)
  176. if err != nil {
  177. response.Error(c, response.TranslateMsg(c, err.Error()))
  178. return
  179. }
  180. service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
  181. Action: service.OauthActionTypeLogin,
  182. Op: f.Op,
  183. Id: f.Id,
  184. DeviceType: "webadmin",
  185. // DeviceOs: ct.Platform(c),
  186. DeviceOs: f.DeviceInfo.Os,
  187. Uuid: f.Uuid,
  188. Verifier: verifier,
  189. Nonce: nonce,
  190. }, 5*60)
  191. response.Success(c, gin.H{
  192. "code": state,
  193. "url": url,
  194. })
  195. }
  196. // OidcAuthQuery
  197. // @Tags Oauth
  198. // @Summary OidcAuthQuery
  199. // @Description OidcAuthQuery
  200. // @Accept json
  201. // @Produce json
  202. // @Success 200 {object} response.Response{data=adResp.LoginPayload}
  203. // @Failure 500 {object} response.Response
  204. // @Router /admin/oidc/auth-query [get]
  205. func (ct *Login) OidcAuthQuery(c *gin.Context) {
  206. o := &api.Oauth{}
  207. u, ut := o.OidcAuthQueryPre(c)
  208. if ut == nil {
  209. return
  210. }
  211. responseLoginSuccess(c, u, ut.Token)
  212. }
  213. func responseLoginSuccess(c *gin.Context, u *model.User, token string) {
  214. lp := &adResp.LoginPayload{}
  215. lp.FromUser(u)
  216. lp.Token = token
  217. lp.RouteNames = service.AllService.UserService.RouteNames(u)
  218. response.Success(c, lp)
  219. }