package fadada import ( "fmt" "net/url" "strings" ) // 默认授权范围:认证信息 + 后续签署所需能力 var defaultAuthScopes = []string{ "ident_info", "seal_info", "signtask_info", "signtask_init", "signtask_file", "organization", "template", } // GenerateEnterpriseAuth 获取企业认证/授权链接(POST /corp/get-auth-url) // 文档见 1.md:corpIdentType 置空由用户在页面选择组织类型。 func (c *Client) GenerateEnterpriseAuth(req *EnterpriseAuthRequest) (*EnterpriseAuthResult, error) { if err := validateEnterpriseAuthRequest(req); err != nil { return nil, err } accessToken, err := c.ensureAccessToken() if err != nil { return nil, err } clientCorpID := strings.TrimSpace(req.ClientCorpID) if clientCorpID == "" { clientCorpID = strings.TrimSpace(req.UnifiedSocialCode) } clientUserID := strings.TrimSpace(req.ClientUserID) if clientUserID == "" { clientUserID = strings.TrimSpace(req.TransactorID) } redirectURL := "" if c.config.Auth != nil { redirectURL = c.config.Auth.RedirectURL } apiReq := &getCorpAuthURLReq{ ClientCorpID: clientCorpID, ClientUserID: clientUserID, AccountName: strings.TrimSpace(req.TransactorMobile), CorpIdentInfo: &corpIdentInfo{ CorpName: strings.TrimSpace(req.CompanyName), // 按官方文档:不传默认为企业;置空让用户在页面选择组织类型 // CorpIdentType: "", CorpIdentNo: strings.TrimSpace(req.UnifiedSocialCode), LegalRepName: strings.TrimSpace(req.LegalPersonName), CorpIdentMethod: []string{CorpIdentMethodLegalRep}, }, // 文档合法值仅 corpName/corpIdentType/corpIdentNo;不传表示都可修改 // CorpNonEditableInfo: , OprIdentInfo: &oprIdentInfo{ UserName: strings.TrimSpace(req.TransactorName), UserIdentType: UserIdentTypeIDCard, UserIdentNo: strings.TrimSpace(req.TransactorID), Mobile: strings.TrimSpace(req.TransactorMobile), OprIdentMethod: []string{OprIdentMethodMobile}, }, OprNonEditableInfo: nil, AuthScopes: append([]string{}, defaultAuthScopes...), RedirectURL: encodeRedirectURL(redirectURL), } res, err := c.http.PostBiz(pathGetCorpAuthURL, accessToken, apiReq) if err != nil { return nil, err } if res.Code != successCode { return nil, fmt.Errorf("获取法大大企业认证链接失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID) } var data getCorpAuthURLData if err := decodeData(res.Data, &data); err != nil { return nil, fmt.Errorf("解析企业认证链接响应失败: %w", err) } if data.AuthURL == "" { return nil, fmt.Errorf("获取法大大企业认证链接失败: authUrl 为空 requestId=%s", res.RequestID) } return &EnterpriseAuthResult{ AuthFlowID: clientCorpID, AuthURL: data.AuthURL, AuthShortURL: data.AuthURL, }, nil } // QueryOrgVerified 查询企业是否已在法大大完成实名(POST /corp/get-identified-status) func (c *Client) QueryOrgVerified(req *QueryOrgIdentityRequest) (bool, error) { result, err := c.QueryOrgIdentity(req) if err != nil { return false, err } return result.Identified, nil } // QueryOrgIdentity 查询企业实名认证状态详情 func (c *Client) QueryOrgIdentity(req *QueryOrgIdentityRequest) (*QueryOrgIdentityResult, error) { if req == nil { return nil, fmt.Errorf("查询请求不能为空") } corpName := strings.TrimSpace(req.CorpName) corpIdentNo := strings.TrimSpace(req.CorpIdentNo) if corpName == "" && corpIdentNo == "" { return nil, fmt.Errorf("企业名称与统一社会信用代码不能同时为空") } accessToken, err := c.ensureAccessToken() if err != nil { return nil, err } res, err := c.http.PostBiz(pathGetCorpIdentifiedStatus, accessToken, &getIdentifiedStatusReq{ CorpName: corpName, CorpIdentNo: corpIdentNo, }) if err != nil { return nil, err } if res.Code != successCode { return nil, fmt.Errorf("查询法大大企业实名状态失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID) } var data getIdentifiedStatusData if err := decodeData(res.Data, &data); err != nil { return nil, fmt.Errorf("解析企业实名状态失败: %w", err) } return &QueryOrgIdentityResult{ Identified: data.IdentStatus, CorpName: corpName, CorpIdentNo: corpIdentNo, }, nil } func validateEnterpriseAuthRequest(req *EnterpriseAuthRequest) error { if req == nil { return fmt.Errorf("认证请求不能为空") } if strings.TrimSpace(req.CompanyName) == "" { return fmt.Errorf("企业名称不能为空") } if strings.TrimSpace(req.UnifiedSocialCode) == "" { return fmt.Errorf("统一社会信用代码不能为空") } if strings.TrimSpace(req.LegalPersonName) == "" { return fmt.Errorf("法人姓名不能为空") } if strings.TrimSpace(req.TransactorName) == "" { return fmt.Errorf("经办人姓名不能为空") } if strings.TrimSpace(req.TransactorMobile) == "" { return fmt.Errorf("经办人手机号不能为空") } if strings.TrimSpace(req.TransactorID) == "" { return fmt.Errorf("经办人身份证号不能为空") } return nil } // encodeRedirectURL 按官方文档对 redirectUrl 做 URL encode;已编码则原样返回 func encodeRedirectURL(raw string) string { raw = strings.TrimSpace(raw) if raw == "" { return "" } if strings.Contains(raw, "%") { if decoded, err := url.QueryUnescape(raw); err == nil && decoded != raw { return raw } } return url.QueryEscape(raw) }