В последнее время я был занят общением со сторонними производителями.,Просто куйте железо, пока горячо,Расчешите Мой процесс при звонке третьим лицам и предоставлении интерфейсов для третьих лиц и решения распространенных проблем,Без лишних слов,Давайте начнем!
Определить документацию по интерфейсу
После общения со сторонней организацией для определения плана разработки и общих идей можно приступать к экспорту документа интерфейса. Документ интерфейса обычно должен включать метод аутентификации интерфейса, алгоритм шифрования, соответствующий методу аутентификации, базовый путь интерфейса (baseUrl) и направление потока данных. Интерфейс включает краткое описание функции интерфейса, метод запроса (); POST/GET), адрес запроса URL-адреса интерфейса и заголовок запроса, описание поля параметра запроса и тип параметра (включая параметр, значение, тип данных, если требуется, другие инструкции), описание поля параметра возврата успешного ответа, состояние сбоя. код и описание. Я подготовил шаблон документа интерфейса в формате MD. Его можно получить, оставив сообщение «Документ интерфейса» на фоне официального аккаунта.
Определить метод аутентификации интерфейса
Поскольку API в системе будет доступен в Интернете, ваш интерфейс будет подвергаться риску того, что каждый сможет его вызвать, поэтому вам необходимо проверить, является ли человек, который в данный момент делает запрос, тем, кто разрешает этот запрос. Во-первых, вы можете добавить некоторые необходимые меры безопасности, такие как шифрование MD5 ключевых полей, таких как переданные пароли, чтобы гарантировать, что конфиденциальные данные, такие как пароли, не передаются в виде обычного текста.
Можно использовать аутентификацию интерфейса Hmac. Платформа предоставляет appId и appSecret, которые соответствуют друг другу и могут использоваться в качестве уникальных идентификаторов. Затем информация о шифровании рассчитывается на основе алгоритма HmacSHA в дополнение к передаче appId и appSecret. , этот интерфейс аутентификации также должен передавать текущую временную метку, чтобы сервер мог идентифицировать незаконные запросы и повысить уникальность сгенерированной авторизации.
Кроме того, вы также можете использовать механизм токенов. Токен представляет собой строку зашифрованных строк, созданную сервером в соответствии с определенными правилами и отправленную клиенту. Клиент будет переносить этот токен (обычно установленный в заголовке) при запросе всех ресурсов. на сервере. Сервер проверяет легитимность этого токена. Я использую токен JWT в качестве примера, чтобы примерно продемонстрировать создание и проверку токена.
const JWTSECRET = "yourJWTSecret" // Сторонний пользовательский JWT-ключ
var TOKENEXPIRETIME = time.Hour * 5 // Срок действия авторизации стороннего пользователя, например: 5 часов.
// Создать JWT token
func generateToken(userName string) (string, error) {
// создать новый JWT token
token := jwt.New(jwt.SigningMethodHS256)
// настраивать token Заявление (полезная нагрузка)
claims := token.Claims.(jwt.MapClaims)
claims["userName"] = userName
claims["exp"] = time.Now().Add(TOKENEXPIRETIME).Unix() // настраивать token срок годности
// Использовать пару ключей token Знак
tokenString, err := token.SignedString([]byte(JWTSECRET))
if err != nil {
log.Println("Failed to generate token:", err)
return "", err
}
// Воля token хранить в Redis середина
err = conf.RedisClient.Set("jwt_token:"+userName, tokenString, time.Hour*5).Err()
if err != nil {
return "", fmt.Errorf("failed to store token in Redis: %v", err)
}
...
return tokenString, nil
}
JWT состоит из трех частей: заголовка, полезных данных и подписи. Заголовок имеет вид {'typ': 'JWT', 'alg': 'HS256'}, в полезных данных хранится действительная информация, такая как срок действия jwt, информация о бизнес-потребностях (конфиденциальная информация не рекомендуется), а подпись зашифрована в формате Base64. Заголовок и полезные данные, зашифрованные с помощью Base64, соединяются со строкой (сначала заголовок), а затем секретная комбинация с солью шифруется с помощью метода шифрования, объявленного в заголовке.
Здесь я сохраняю сгенерированный токен JWT и соответствующую информацию о пользователе в Redis и устанавливаю срок действия пары ключ-значение Redis. Во время проверки вы можете получить имя пользователя и соответствующий токен, чтобы определить, прошла ли аутентификация. Если срок действия токена истечет, он будет автоматически обновлен и повторно создан.
// Верифитокен
func ValidateToken(tokenString string) bool {
// анализировать JWT token
token, _ := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
// Убедитесь, что алгоритм подписи HS256
if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
return false, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
}
// Возвращает ключ, используемый для проверки подписи
return []byte(JWTSECRET), nil
})
// проверять token Это действительно?
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// Получить имя пользователя
userName := claims["userName"].(string)
// от Redis середина Сохранять token
storedToken, err := conf.RedisClient.Get("jwt_token:" + userName).Result()
log.Println("storedToken=", storedToken)
if err != nil {
return false
}
// проверять token Связано ли это с хранимым token последовательный
if tokenString != storedToken {
return false
}
// исследовать token То ли срок его действия истек, Восстановить, если срок годности истек
expirationTime := time.Unix(int64(claims["exp"].(float64)), 0)
if time.Now().After(expirationTime) {
// Регенерировать token
newToken, err := generateToken(userName)
if err != nil {
return false
}
// возобновлять Redis серединахранится token
err = conf.RedisClient.Set("jwt_token:"+userName, newToken, time.Hour*24*7).Err()
if err != nil {
return false
}
}
return true
} else {
return false
}
}
Определить срок действия токена
вышеJWTпроверять Часть того, что мы упомянули вtokenАвтоматически по истечении срока действия Регенерировать,Почему автоматическое продление? Прежде всего, нужно учитывать конкретную бизнес-ситуацию.,JWTнастройки по истечении времени,Однажды истекло время,Весь интерфейс будет недоступен,Пользователю необходимо снова войти в систему для аутентификации, чтобы снова получить токен.,Но это повлияет на нормальную работу бизнеса。В обычных обстоятельствах это будетнастраивать Автоматическое продление,Пользователям будет разрешено снова войти в систему только при определенных условиях.
Push и авторизация пользователей с обеих сторон
Возможно, при подключении к третьей стороне другой стороне необходимо отправить информацию о пользователе на нашу платформу, поэтому необходимо предоставить третьей стороне интерфейс принудительной отправки пользователя, включая функцию добавления, удаления и изменения пользователей. Здесь следует отметить, что пользователи, отправленные третьей стороной, должны отличаться от исходных пользователей в системе, например, путем добавления поля идентификации внешнего пользователя. После различения для внешних пользователей можно выполнить специальную авторизацию. запрос разрешений для разных интерфейсов для разных пользователей может основываться на Текущая пользовательская система устанавливает простой RBAC для назначения ролей пользователям и предоставления различных разрешений интерфейса пользователям в разных ролях.
Переадресация запроса на специальный метод входа
Эта ссылка не обязательно может быть задействована в вашем процессе разработки. Мое бизнес-требование заключается в том, что пользователи с трехсторонним доступом должны войти в систему через предоставляемый ими интерфейс распознавания лиц, а используемые пользователи также должны быть ранее переданы нам. пользователи. Клиент отправит распознанное изображение лица в формате Base64 и токен, зарегистрированный в нашей системе, на сервер. Сервер будет использовать токен проверки авторизации для доступа к интерфейсу распознавания лиц, предоставленному третьей стороной, и результатам сопоставления лиц, возвращенным третьей стороной. party будет отправлена на сервер, а соответствующий результат будет обработан сервером и возвращен клиенту.
Пример логики кода обработки на стороне сервера выглядит следующим образом:
func (U *UserServer) FaceRecognition(ctx context.Context, req *pb.FaceRecognitionReq) (resp *pb.FaceRecognitionResp, err error) {
cuser, err := U.Auth(ctx)
if err != nil {
return nil, error.New("Проверка пользователя не удалась")
}
userInfo, err := new(models.User).View(cuser.UserId)
url := BaseURL + "/faceRecognition" // URL-адрес трехстороннего распознавания лиц
// Создайте запрос на распознавание лиц
reqBody := map[string]interface{}{
"image": req.Img,
"userId": userInfo.UserId,
}
// Воля тело запроса конвертировано в формат JSON
reqBodyJSON, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
httpReq, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(reqBodyJSON))
if err != nil {
return nil, err
}
// Получить сторонний токен
authorization := ExternalLogin(userInfo.UserId)
// настройки заголовков HTTP-запросов
httpReq.Header.Set("Authorization", authorization)
httpReq.Header.Set("Content-Type", "application/json") // Указывает данные в формате JSON
// Отправить HTTP-запрос на распознавание лиц
httpClient := http.DefaultClient
httpResp, err := httpClient.Do(httpReq)
if err != nil {
return nil, err
}
defer httpResp.Body.Close()
// анализироватьHTTPответ
respBody, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return nil, err
}
// Преобразовать данные ответа Воли в строку
respStr := string(respBody)
// анализировать данные ответа HTTP
var respData struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
DetectFaceRet bool `json:"detectFaceRet"`
Reason string `json:"reason"`
} `json:"data"`
}
err = json.Unmarshal([]byte(respStr), &respData)
if err != nil {
return nil, err
}
// Построение ответа RPC
resp = &pb.FaceRecognitionResp{
DetectFaceRet: respData.Data.DetectFaceRet,
Reason: respData.Data.Reason,
}
return resp, nil
}
Часто задаваемые вопросы и решения
Интерфейс возвращает 400
Эта проблема очень странная. Запрос может быть успешным с помощью почтальона, но при запросе интерфейса другой стороны с использованием интерфейса возвращается 400. Затем я настроил http-сервер go для его получения, и его также можно получить. Я некоторое время растерялся и обратился за помощью к энтузиасту.
Я последовал методу своего брата и сравнил свой запрос на доступ с запросом Почтальона. Они казались абсолютно одинаковыми, пока я не увидел яму, которую я зарыл в URL-адресе. Двойные кавычки, которые появляются в URL-адресе в Postman, будут закодированы, но я написал это в коде:
url := BaseURL + `/xxxx?reqID="` + randomString + `"`
Здесь обратный апостроф представляет собой строковый литерал и не поддерживает escape-последовательности. Литеральная необработанная литеральная строка означает, что она будет выглядеть так, как вы ее задаете. Таким образом, двойные кавычки здесь не экранируются, что приводит к неправильному пути и возвращению ошибки 400 [/face Covering].
Интерфейс возвращает 404
404 означает, что интерфейс не найден. Возможно, имя интерфейса неверно или служба загружена. Также возможно, что последняя конфигурация стороннего шлюза не была обновлена. Эту проблему необходимо подтвердить. сторонний доковый персонал.
Интерфейс возвращает 500
Существует высокая вероятность того, что это ошибка в интерфейсе или данных другой стороны, и это также необходимо подтвердить у стороннего персонала по стыковке.
Интерфейс неудачный или неудачный
Это может быть сетевая проблема с другой стороной или сторонняя платформа перезапускает службу. Об этой проблеме также необходимо сообщить им для обработки.
Интерфейс возвращает пустой
Проблемы со сторонней сетью приводят к недоступности интерфейса. Обратите внимание на проблему с пустым интерфейсом, вызванную этой ситуацией. Вам следует добавить в интерфейс обработку инициализации и обнаружения пустости, иначе запланированное задание заполнит ваш журнал ошибками.
Определить передачу значения фиксированного поля
Необходимо подтвердить, что все необходимые параметры в документе интерфейса были переданы, а также определить, какие поля требуют фиксированных значений и были ли фиксированные значения изменены другой стороной, например уникальный идентификатор производителя, пользователь исходные фиксированные значения и т. д.
Недействительность токена и проблемы с кешем Redis
Если срок действия токена истечет и он не будет повторно получен вовремя или не будет продлен, токен станет недействительным. Если срок действия токена истечет, интерфейс не сможет пройти аутентификацию и его нельзя будет использовать. Также возможно, что срок действия токена несовместим. со временем истечения срока действия, установленным в Redis. Поэтому мы должны уделять внимание обработке ошибок недействительности токена, оперативно запрашивать интерфейс аутентификации для повторного получения токена, обновлять новый токен до redis и единообразно устанавливать срок действия.
Следуйте за Гонгом, чтобы не заблудиться!