فهرست منبع

钉钉免登显示钉钉用户名和头像,配置XSRF,修复一些BUG

LawyZHENG 4 سال پیش
والد
کامیت
9141487aa3
7فایلهای تغییر یافته به همراه79 افزوده شده و 15 حذف شده
  1. 15 0
      conf/app.conf.example
  2. 1 2
      conf/enumerate.go
  3. 17 3
      controllers/AccountController.go
  4. 0 4
      models/Member.go
  5. 1 1
      models/TeamMember.go
  6. 44 4
      utils/dingtalk/dingtalk.go
  7. 1 1
      views/account/login.tpl

+ 15 - 0
conf/app.conf.example

@@ -7,6 +7,7 @@ runmode = "${MINDOC_RUN_MODE||dev}"
 sessionon = true
 sessionname = mindoc_id
 copyrequestbody = true
+enablexsrf = true
 
 #系统完整URL(http://doc.iminho.me),如果该项不设置,会从请求头中获取地址。
 baseurl="${MINDOC_BASE_URL}"
@@ -209,6 +210,20 @@ log_level="${MINDOC_LOG_LEVEL||Alert}"
 # 是否异步生成日志,默认是 true
 log_is_async="${MINDOC_LOG_IS_ASYNC||TRUE}"
 
+##########钉钉应用相关配置##############
+
+# 企业钉钉ID
+dingtalk_corpid="${MINDOC_DINGTALK_CORPID}"
+
+# 钉钉AppKey
+dingtalk_app_key="${MINDOC_DINGTALK_APPKEY}"
+
+# 钉钉AppSecret
+dingtalk_app_secret="${MINDOC_DINGTALK_APPSECRET}"
+
+# 钉钉登录默认只读账号
+dingtalk_tmp_reader="${MINDOC_DINGTALK_READER}"
+
 
 
 

+ 1 - 2
conf/enumerate.go

@@ -20,8 +20,7 @@ const CaptchaSessionName = "__captcha__"
 const RegexpEmail = "^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
 
 //允许用户名中出现点号
-// const RegexpAccount = `^[a-zA-Z][a-zA-Z0-9\.-]{2,50}$`
-const RegexpAccount = `[a-zA-Z0-9\.-]{2,50}$`
+const RegexpAccount = `^[a-zA-Z][a-zA-Z0-9\.-]{2,50}$`
 
 // PageSize 默认分页条数.
 const PageSize = 10

+ 17 - 3
controllers/AccountController.go

@@ -32,9 +32,12 @@ func (c *AccountController) referer() string {
 
 func (c *AccountController) Prepare() {
 	c.BaseController.Prepare()
-	c.EnableXSRF = true
+	c.EnableXSRF = beego.AppConfig.DefaultBool("enablexsrf", true)
 	c.Data["xsrfdata"] = template.HTML(c.XSRFFormHTML())
 	c.Data["corpID"] = beego.AppConfig.String("dingtalk_corpid")
+	if !c.EnableXSRF {
+		return
+	}
 	if c.Ctx.Input.IsPost() {
 		token := c.Ctx.Input.Query("_xsrf")
 		if token == "" {
@@ -138,7 +141,7 @@ func (c *AccountController) Login() {
 func (c *AccountController) DingTalkLogin() {
 	c.Prepare()
 
-	code := c.GetString("code")
+	code := c.GetString("dingtalk_code")
 	if code == "" {
 		c.JsonResult(500, "获取身份信息失败", nil)
 	}
@@ -160,7 +163,14 @@ func (c *AccountController) DingTalkLogin() {
 		c.StopRun()
 	}
 
-	username, err := dingtalkAgent.GetUserNameByCode(code)
+	userid, err := dingtalkAgent.GetUserIDByCode(code)
+	if err != nil {
+		beego.Warn("钉钉自动登录失败 ->", err)
+		c.JsonResult(500, "自动登录失败", nil)
+		c.StopRun()
+	}
+
+	username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
 	if err != nil {
 		beego.Warn("钉钉自动登录失败 ->", err)
 		c.JsonResult(500, "自动登录失败", nil)
@@ -171,6 +181,10 @@ func (c *AccountController) DingTalkLogin() {
 	if err == nil {
 		member.LastLoginTime = time.Now()
 		_ = member.Update("last_login_time")
+		member.Account = username
+		if avatar != "" {
+			member.Avatar = avatar
+		}
 
 		c.SetMember(*member)
 	}

+ 0 - 4
models/Member.go

@@ -179,10 +179,6 @@ func (m *Member) httpLogin(account, password string) (*Member, error) {
 		return nil, ErrMemberAuthMethodInvalid
 	}
 
-	tmpH := md5.New()
-	tmpH.Write([]byte(password))
-	password = strings.ToUpper(hex.EncodeToString(tmpH.Sum(nil)))
-
 	val := url.Values{
 		"account":  []string{account},
 		"password": []string{password},

+ 1 - 1
models/TeamMember.go

@@ -227,7 +227,7 @@ limit ?;`
 	for _, member := range members {
 		item := KeyValueItem{}
 		item.Id = member.MemberId
-		item.Text = member.Account + "(" + member.RealName + ")"
+		item.Text = member.Account + "[" + member.RealName + "]"
 		items = append(items, item)
 	}
 	result.Result = items

+ 44 - 4
utils/dingtalk/dingtalk.go

@@ -27,8 +27,8 @@ func NewDingTalkAgent(appSecret, appKey string) *DingTalkAgent {
 	}
 }
 
-// GetUserNameByCode 通过临时code获取当前用户信息
-func (d *DingTalkAgent) GetUserNameByCode(code string) (string, error) {
+// GetUserIDByCode 通过临时code获取当前用户ID
+func (d *DingTalkAgent) GetUserIDByCode(code string) (string, error) {
 	urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/user/getuserinfo")
 	if err != nil {
 		return "", err
@@ -62,8 +62,48 @@ func (d *DingTalkAgent) GetUserNameByCode(code string) (string, error) {
 		return "", errors.New(fmt.Sprintf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string)))
 	}
 
-	username := rdata["name"].(string)
-	return username, nil
+	userid := rdata["userid"].(string)
+	return userid, nil
+}
+
+// GetUserNameAndAvatarByUserID 通过userid获取当前用户姓名和头像
+func (d *DingTalkAgent) GetUserNameAndAvatarByUserID(userid string) (string, string, error) {
+	urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/topapi/v2/user/get")
+	if err != nil {
+		return "", "", err
+	}
+
+	query := url.Values{}
+	query.Set("access_token", d.AccessToken)
+
+	urlEndpoint.RawQuery = query.Encode()
+	urlPath := urlEndpoint.String()
+
+	resp, err := http.PostForm(urlPath, url.Values{"userid": {userid}})
+	if err != nil {
+		return "", "", err
+	}
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return "", "", err
+	}
+
+	// 解析钉钉返回数据
+	var rdata map[string]interface{}
+	err = json.Unmarshal(body, &rdata)
+	if err != nil {
+		return "", "", err
+	}
+
+	errcode := rdata["errcode"].(float64)
+	if errcode != 0 {
+		return "", "", errors.New(fmt.Sprintf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string)))
+	}
+
+	userinfo := rdata["result"].(map[string]interface{})
+	username := userinfo["name"].(string)
+	avatar := userinfo["avatar"].(string)
+	return username, avatar, nil
 }
 
 // GetAccesstoken 获取钉钉请求Token

+ 1 - 1
views/account/login.tpl

@@ -99,7 +99,7 @@
                         })
 
                         var formData = $("form").serializeArray()
-                        formData.push({"name": "code", "value": info.code})
+                        formData.push({"name": "dingtalk_code", "value": info.code})
 
                         $.ajax({
                             url: "{{urlfor "AccountController.DingTalkLogin"}} ",