Smarthome API 说明文档
版本: 1.0 
发布日期: 2024-03-28 
历史记录 | 修订日期 | 版本 | 作者 | 说明 | | --------- | ---- | ---------- | -------- | | 2024-3-28 | V1.0 | alva.huang | 初始版本 | | 2024-5-11 | V1.0.1 | alva.huang | 增加头像上传,手机验证码 |
[toc]
# 前言 ## 概述 本文档旨在说明爱智居服务端的API接口,帮助开发人员如何使用smarthome api 进行开发,并详细介绍了各API的功能,调用方式,返回结果和错误码。 ## 范围说明 此开发文档只针对智能家居控制app,小程序,以及相应的控制端app,面板app等的开发。 # 账户系统 账户系统主要功能是用户注册,登录,修改密码,忘记密码,注销账号。用户信息维护和更新。用户权限控制。角色映射等和用户相关的功能。 ## HTTP返回状态码说明 200-299 请求成功 400-499 请求失败,客户端参数或信息错误 500-599 请求失败,服务端错误 | 状态码 | 说明 | | ------ | --------------------------------------------- | | 200 | 请求成功 | | 201 | 新增成功 | | 204 | 删除成功/更新成功 | | 401 | 请求失败,无权限,没有登陆认证或认证token错误 | | 403 | 请求失败,无权限 | | 404 | 请求失败,资源不存在 | | 405 | 请求失败,请求方法不支持 | | 406 | 请求失败,参数错误 | | 400 | 请求失败,参数错误 | | 408 | 请求失败,请求超时 | | 415 | 请求失败,不支持的媒体类型 | | 500 | 请求失败,服务端内部错误 | ## 用户登陆认证 ### 微信用户注册登陆接口 用户通过微信小程序登陆,并使用微信code换取token,调用此接口完成注册和登录。 当用户第一次使用微信小程序登陆,并且没有绑定过账号时,需要传入手机号码和验证码,进行注册绑定手机号码。后续使用微信小程序登陆,不需要传入手机号码和验证码。 POST 请求URL: [https://account.izhiju.cn/realms/zhiju/protocol/openid-connect/token](https://account.izhiju.cn/realms/zhiju/protocol/openid-connect/token) 请求头参数: Content-Type: application/x-www-form-urlencoded 请求体参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ------------- | -------- | -------------- | --------------------------------------------- | | client_id | string | wechatapp | 客户端id,微信小程序固定为wechatapp,必须字段 | | client_secret | string | 平台相关的密钥 | 客户端密钥,必须字段 | | grant_type | string | password | 授权类型,固定为password,必须字段 | | wechatCode | string | code | wx.login()返回的code,必须传值 | | smsCode | string | NULL | 手机收到的验证码,已绑定的用户可不传 | | phoneNumber | string | NULL | 手机号,可不传 | | areaCode | string | NULL | 区号,可不传 | 返回结果: 1. 成功,状态码200,返回如下内容: ```json { "access_token": "eyJhbGciO", //token 可做为调用其它接口的授权凭证 "expires_in": 1800, //token有效期,单位秒 "refresh_expires_in": 1800, //refresh_token有效期,单位秒 "refresh_token": "eyJhbGci", //refresh_token,用于刷新token "token_type": "Bearer", //token类型,Bearer "not-before-policy": 0, "session_state": "2f2bd023-793e-4abc-a067-7dd4d49705a3", "scope": "profile" //token权限,profile表示用户信息 } ``` 2. 微信授权码无效,状态码401,返回如下内容: ```json { "error": "wechat_code_invalid", "error_description": "微信授权码无效,过期或已使用" } ``` 3. 手机验证码错误,状态码401,返回如下内容: ```json { "error": "sms_code_invalid", "error_description": "手机验证码无效" } ``` 4. 手机号已绑定其他账号,状态码401,返回如下内容: ```json { "error": "invalid_grant", "error_description": "Invalid user credentials" } ``` ### 应用客户端用户名密码登陆认证接口 POST 请求URL: [https://account.izhiju.cn/realms/zhiju/protocol/openid-connect/token](https://account.izhiju.cn/realms/zhiju/protocol/openid-connect/token) 请求头参数: Content-Type: application/x-www-form-urlencoded 请求体参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ------------- | -------- | -------------- | --------------------------------------------- | | client_id | string | wechatapp | 客户端id,微信小程序固定为wechatapp,必须字段 | | client_secret | string | 平台相关的密钥 | 客户端密钥,必须字段 | | grant_type | string | password | 授权类型,固定为password,必须字段 | | username | string | username | 用户名 | | password | string | user password | 用户秘密 | | | | | | 返回结果: 1. 成功,状态码200,返回结果如下 ```json { "access_token": "eyJhbGciO", //token 可做为调用其它接口的授权凭证 "expires_in": 1800, //token有效期,单位秒 "refresh_expires_in": 1800, //refresh_token有效期,单位秒 "refresh_token": "eyJhbGci", //refresh_token,用于刷新token "token_type": "Bearer", //token类型,Bearer "not-before-policy": 0, "session_state": "2f2bd023-793e-4abc-a067-7dd4d49705a3", "scope": "profile" //token权限,profile表示用户信息 } ``` 2. 客户端授权无效,用户名或秘密错误,状态码401 ```json { "error": "invalid_grant", "error_description": "Invalid user credentials" } ``` 3. 客户端id或secret错误,状态码401 ```json { "error": "invalid_client", "error_description": "Invalid client or Invalid client credentials" } ``` 4. 不支持的授权类型,状态码401 ```json { "error": "unsupported_grant_type", "error_description": "Unsupported grant_type" } ``` ### 应用客户端手机号码密码登陆认证接口 POST 请求URL: [https://account.izhiju.cn/realms/zhiju/protocol/openid-connect/token](https://account.izhiju.cn/realms/zhiju/protocol/openid-connect/token) 请求头参数: Content-Type: application/x-www-form-urlencoded 请求体参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ------------- | -------- | -------------- | --------------------------------------------- | | client_id | string | wechatapp | 客户端id,微信小程序固定为wechatapp,必须字段 | | client_secret | string | 平台相关的密钥 | 客户端密钥,必须字段 | | grant_type | string | password | 授权类型,固定为password,必须字段 | | phoneNumber | string | | 手机号码 | | areaCode | string | 86 | 国家区号 | | password | string | user password | 用户秘密 | | | | | | 返回结果: 1. 成功,状态码200,返回结果如下: ```json { "access_token": "eyJhbGciO", //token 可做为调用其它接口的授权凭证 "expires_in": 1800, //token有效期,单位秒 "refresh_expires_in": 1800, //refresh_token有效期,单位秒 "refresh_token": "eyJhbGci", //refresh_token,用于刷新token "token_type": "Bearer", //token类型,Bearer "not-before-policy": 0, "session_state": "2f2bd023-793e-4abc-a067-7dd4d49705a3", "scope": "profile" //token权限,profile表示用户信息 } ``` 2. 客户端授权无效,手机号或秘密错误,状态码401 ```json { "error": "invalid_grant", "error_description": "Invalid user credentials" } ``` 3. 客户端id或secret错误,状态码401 ```json { "error": "invalid_client", "error_description": "Invalid client or Invalid client credentials" } ``` 4. 不支持的授权类型,状态码401 ```json { "error": "unsupported_grant_type", "error_description": "Unsupported grant_type" } ``` ## 用户信息管理 ### 获取用户信息 GET 请求URL: [https://account.izhiju.cn/realms/zhiju/account](https://account.izhiju.cn/realms/zhiju/account) 请求头参数: Content-Type: application/json Authorization: Bearer {{token}} 返回结果: 1. 未授权,状态码401 ```json { "error": "HTTP 401 Unauthorized", "error_description": "For more on this error consult the server log at the debug level." } ``` 2. 成功,状态码200, 返回如下内容: ```json { "id": "456637c0-c3a0-412a-8aeb-37f518ac11ed", "username": "alva", "firstName": "alva1", "lastName": "huang", "email": "alva@izhiju.cn", "emailVerified": false, "attributes": { "phoneNumber": [ "18680533727" ], "picture": [ "https://account.izhiju.cn/resources/2cyxv/account/keycloak.v3/logo.svg" ], "nickname": ["test"] } } ``` ### 通过用户ID获取用户信息 GET 请求 url: https://account.izhiju.cn/realms/zhiju/sms/user/{{userId}} 请求头参数: Content-Type: application/json Authorization: Bearer {{token}} 路径参数:{{userId}} 用户ID 返回结果: 1. 成功,状态码200, 返回如下内容: { "id": "456637c0-c3a0-412a-8aeb-37f518ac11ed", "username": "test", "email": "test@example.com", "attributes": { "phoneNumber": [ "+86 15889485045" ], "nickname": [ "testtest" ], "picture": [ "https://account.izhiju.cn/realms/zhiju/avatar/by-userid/3333c9a4-52e1-4ff8-bfb2-d17ba01ad528" ] } } 2. 为登陆或token过期,状态码401,返回如下内容: ```json { "error": "HTTP 401 Unauthorized", "error_description": "For more on this error consult the server log at the debug level." } ``` 3. 用户不存在,状态码404,返回如下内容: ```json { "error_description": "user not found", "error": "user_not_found." } ``` ### 通过用户手机号获取用户信息 GET 请求 url: https://account.izhiju.cn/realms/zhiju/sms/user/byphone?phoneNumber=12345678901 请求头参数: Content-Type: application/json Authorization: Bearer {{token}} 查寻参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ------------- | -------- | -------------- | --------------------------------------------- | | phoneNumber | string | | 用户手机号 | | areaCode | string | 86 | 手机号所属地区码,默认不填为中国86 | 返回结果: 1. 成功,状态码200, 返回如下内容: { "id": "456637c0-c3a0-412a-8aeb-37f518ac11ed", "username": "test", "email": "test@example.com", "attributes": { "phoneNumber": [ "+86 1111234434" ], "nickname": [ "testtest" ], "picture": [ "https://account.izhiju.cn/realms/zhiju/avatar/by-userid/3333c9a4-52e1-4ff8-bfb2-d17ba01ad528" ] } } 1. 为登陆或token过期,状态码401,返回如下内容: ```json { "error": "HTTP 401 Unauthorized", "error_description": "For more on this error consult the server log at the debug level." } ``` 3. 用户不存在,状态码404,返回如下内容: ```json { "error_description": "user not found", "error": "user_not_found." } ``` ### 更新用户信息 POST 请求URL: [https://account.izhiju.cn/realms/zhiju/account](https://account.izhiju.cn/realms/zhiju/account) 请求头参数: Content-Type: application/json Authorization: Bearer {{token}} ```json { "id": "456637c0-c3a0-412a-8aeb-37f518ac11ed", "username": "alva", //// username 6-12个字符,仅支持字母、数字和下划线,不区分大小写 "firstName": "alva1", "lastName": "huang", "email": "alva@izhiju.cn", "emailVerified": false, "attributes": { "phoneNumber": [ "18680533727" ], "picture": [ "https://account.izhiju.cn/resources/2cyxv/account/keycloak.v3/logo.svg" ] } } ``` 返回结果: 1. 未认证授权,状态码401, token错误或过期 ```json { "error": "HTTP 401 Unauthorized", "error_description": "For more on this error consult the server log at the debug level." } ``` 2. 更新成功,状态码204, 无内容返回 3. 更新失败,状态码400,下面为用户名不可修改返回的错误信息 ```json { "errors": [ { "field": "username", "errorMessage": "error-user-attribute-read-only", "params": [ "${username}" ] }, { "field": "username", "errorMessage": "readOnlyUsernameMessage", "params": [ "${username}" ] } ] } ``` ### 用手机号注册用户 POST 请求 url: https://account.izhiju.cn/realms/zhiju/sms/user 请求头参数: Content-Type: application/x-www-form-urlencoded 请求体参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ------------- | -------- | -------------- | --------------------------------------------- | | phoneNumber | string | | 用户手机号 | | areaCode | string | 86 | 手机号所属地区码,默认不填为中国86 | | password | string | | 密码,6-12个字符,字母、数字 | | smsCode | string | | 短信验证码,6位数字 | 返回结果: 1. 成功,状态码200, 返回如下内容: ```json { "id": "456637c0-c3a0-412a-8aeb-37f518ac11ed", "username": "alva", //// username 6-12个字符,仅支持字母、数字和下划线,不区分大小写 "firstName": "alva1", "lastName": "huang", "email": "alva@izhiju.cn", "emailVerified": false, "attributes": { "phoneNumber": [ "18680533727" ], "picture": [ "https://account.izhiju.cn/resources/2cyxv/account/keycloak.v3/logo.svg" ] } } ``` 2. 状态码400, 返回如下内容: ```json { "error": "phonenumber_is_empty", "error_description": "Must inform a cellphone number." } ``` ```json { "error": "phonenumber_area_not_supported", "error_description": "This area is not supported" } ``` ```json { "error": "password_is_empty", "error_description": "Must inform a password." } ``` ```json { "error": "user_already_exists", "error_description": "用户已存在,无需重复注册" } ``` ```json { "error": "user_already_exists", "error_description": "用户名和手机号冲突,请更换手机号" } ``` ```json { "error": "invalid_verification_code", "error_description": "Invalid verification code" } ``` ### 修改用户手机号码 URL: put {{url}}/sms/update-profile http/1.1 请求头参数: Authorization: Bearer {{token}} Content-Type: application/x-www-form-urlencoded 请求体参数: &smsCode=867014 &phoneNumber=18680533727 &areaCode=86 1. 修改成功,状态码204, 无内容返回 2. 未登录,状态码401, token错误或过期 3. 失败,状态码400,参数错误 ### 修改用户秘密 #### 通过手机验证码重置密码 URL: put {{url}}/sms/update-profile/reset-password 请求头参数: Authorization: Bearer {{token}} Content-Type: application/x-www-form-urlencoded 请求体参数: password=4223261 //密码规则 8-16个字符,需至少包含大、小写字母和数字 &smsCode=531495 //短信验证码 #### 通过手机验证码重置密码 URL: put {{url}}/sms/update-profile/forgot-password http/1.1 请求头参数: Content-Type: application/x-www-form-urlencoded 请求体参数: password=422326 &smsCode=867014 &phoneNumber=18680533727 &areaCode=86 #### 通过旧密码修改密码 URL: put {{url}}/sms/update-profile/update-password http/1.1 请求头参数: Authorization: Bearer {{token}} Content-Type: application/x-www-form-urlencoded 请求体参数: password=422326 //新密码 8-16个字符,需至少包含大、小写字母和数字 &oldPassword=4223261 //旧密码 #### 返回结果: 1. 成功,状态码204, 无内容返回 2. 未登录,状态码401, token错误或过期 ```json { "error": "HTTP 401 Unauthorized", "error_description": "For more on this error consult the server log at the debug level." } ``` 3. 失败,状态码400,参数错误 ### 小程序用户名片二维码格式 ```js { "app": "smarthome", //app值固定为smarthome "uid": "3333c9a4-52e1-4ff8-bfb2-d17ba01ad528" //其中uid值是用户id } ``` ## 发送短信验证码 POST 请求URL: [https://account.izhiju.cn/realms/zhiju/sms/verification-code](https://account.izhiju.cn/realms/zhiju/sms/verification-code) 请求头参数: Content-Type: application/x-www-form-urlencoded 请求体参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ----------- | -------- | ------ | ------------------------ | | areaCode | string | 86 | 手机号所属的区号,默认86 | | phoneNumber | string | | 手机号,11位数字 | ### 返回结果 1. 正确状态码200,返回结果: ```json { "expires_in": 1714988276153, "resend_expires": 1714988036153, "status": 1 } ``` 2. 错误状态码400,参数错误,返回结果: ```json { "error": "sms_code_send_error", "error_description": "短信发送失败,请检查手机号码或网络状态" } ``` 3. 错误状态码400,参数数据错误,返回结果: ```json { "error": "phonenumber_is_empty", "error_description": "Must inform a cellphone number." } ``` 4. 错误状态码400,参数数据错误,返回结果: ```json { "error": "area_not_supported", "error_description": "不支持该区号" } ``` 5. 错误状态码400,参数数据错误,返回结果: ```json { "error": "sms_code_send_error", "error_description": "短信发送失败,请检查手机号码或网络状态" } ``` ## 通过短信验证码修改手机号码 POST 请求URL:https://account.izhiju.cn/realms/zhiju/sms/update-profile 请求头参数: Authorization: Bearer {{token}} Content-Type: application/x-www-form-urlencoded 请求体参数: | 参数名 | 参数类型 | 默认值 | 说明 | | ----------- | -------- | ------ | ------------------------ | | areaCode | string | 86 | 手机号所属的区号,默认86 | | phoneNumber | string | | 手机号,11位数字 | | smsCode | string | | 短信验证码,6位数字 | ### 修改手机号码返回结果 1. 修改成功,状态码204,无内容返回 2. 错误状态码401,token过期或错误,返回结果: ```json { "error_description": "need login", "error": "auth_invalid" } ``` 3. 错误状态码400,返回结果: ```json { "error_description": "Must inform a phone number", "error": "phone_number_code_empty" } ``` 4. 错误状态码400,smsCode错误,返回结果: ```json { "error_description": "Token code cannot be empty", "error": "smscode_be_empty" } ``` ## 用户头像管理 ### 头像配置 spi-avatar-provider-config- | 参数名 | 参数类型 | 默认值 | 说明 | | -------------- | ------------- | ----------- | ------------------------------------------ | | defaultAvatar | ```string``` | ```/``` | URL for default avatar | | alwaysRedirect | ```boolean``` | ```false``` | Should always redirect to static image url | | defaultSize | ```string``` | ```lg``` | Default avatar size | | storageService | ```string``` | ```file``` | Provider to store avatar files | ### 头像存储配置 spi-avatar-storage-file- | 参数名 | 参数类型 | 默认值 | 说明 | | -------------- | ------------ | --------------------------------------------------- | --------------------------------------------- | | root | ```string``` | ```/``` | FS storage root path | | route | ```string``` | ```/{realm}/avatar/{avatar_id}/avatar-{size}.png``` | URL and path to avatar file (Not need change) | | baseurl | ```string``` | ```/realms/``` | Keycloak base url | | default-avatar | ```string``` | ```/{realm}/avatar/default.png``` | Path to default avatar | ### 接口基本参数 | 参数名 | 参数类型 | 默认值 | 说明 | | ------ | ------------------------------------------------------- | -------------------------- | ---------------- | | size | ```enum("xs", "sm", "md", "lg", "xl", "xxl")``` | ```{Config.defaultSize}``` | Avatar file size | | format | ```enum("raw", "json")``` | ```raw``` | Response format | ### 通过用户ID获取头像 请求: GET /realms/{realm}/avatar/by-userid/{user_id} #### 返回结果 1. 没有size参数时,返回默认lg大头像,没有format参数时,默认format为raw,返回原始图片 2. 请求参数中指定format参数为json时,返回json格式数据: ```js { status: 1, avatar: "", // avatar url for lg avatar_tpl: "", // avatar url template, placeholder: %s } ``` ### 通过用户名获取头像 Request: ``` GET /realms/{realm}/avatar/by-username/{username} ``` Respose (While format=json): ```js { status: 1, avatar: "", // avatar url for lg avatar_tpl: "", // avatar url template, placeholder: %s } ``` ### 获取默认头像 Request: ``` GET /realms/{realm}/avatar/default ``` Respose (While format=json): ```js { status: 1, avatar: "", // avatar url for lg avatar_tpl: "", // avatar url template, placeholder: %s } ``` ### 上传头像 Request: ``` POST /realms/{realm}/avatar Authorization: Bearer {{token}} Content-Type: multipart/form-data image= ```