公司的智能家居产品需要接入语音控制,目前在对接阿里语音的天猫精灵
对接天猫精灵的第一步是完成outh鉴权
https://doc-bot.tmall.com/docs/doc.htm?spm=0.7629140.0.0.84a01780RQrNoT&treeId=393&articleId=106999&docType=1
鉴权的博客可以参照如下博客
1.Java实现Aligenie天猫精灵OAuth2.0认证授权流程
https://blog.csdn.net/willianfu/article/details/87464528
免登录式的
https://blog.csdn.net/weixin_41581158/article/details/81120028
带有登录的
贴个代码说说自己的实现
天猫精灵的文档还是很详细的,第一步是登录认证,认证OK之后重定向天猫精灵的地址(带上code的)
登录过程还是必要的,例如我的登录过程,登录上报了单元房ID,这样就把这个天猫精灵和房屋建立关系了,通过这个code赋值的token也是单元房ID,这样在设备控制和查询的时候通过token就知道是查询哪个单元房的设备了
第一步登录,将回调地址放入map中,等待登录成功后回调地址+code信息重定向
@RequestMapping(value = "/login") public String login(@ModelAttribute LoginForm loginForm, HttpServletRequest request) { String unicede = IdUtil.getId() + ""; String repsonse = "login"; try { //构建OAuth 授权请求 OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request); //if (oauthRequest.getClientId() != null && oauthRequest.getClientId().equals(clientId)) { LOG.info("clientID:" + oauthRequest.getClientId()); //利用oauth授权请求设置responseType,目前仅支持CODE,另外还有TOKEN String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE); //进行OAuth响应构建 OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND); builder.setParam("state", oauthRequest.getState()); //得到到客户端重定向地址 String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI); //构建响应 OAuthResponse response = builder.location(redirectURI).buildQueryMessage(); String responceUri = response.getLocationUri(); //将url放入map,待用户登录后填上code做回调 loginForm.setUnicode(unicede); map.put(unicede, responceUri); //} } catch (OAuthSystemException e) { LOG.error("处理获取code请求时发生异常", e); repsonse = "error"; } catch (OAuthProblemException e) { LOG.error("处理获取code请求时发生异常", e); repsonse = "error"; } return repsonse; }
第二部登录鉴权,登录成功重定向至天猫精灵服务器,即返回天猫精灵code
@RequestMapping(value = "/loginSucess") public String add(@ModelAttribute LoginForm loginForm) { String uniCode = loginForm.getUnicode(); String redirectURL = map.get(uniCode); if (redirectURL == null) { LOG.error("用户回调url为null,需要重新登录"); return "error"; } map.remove(uniCode); //houseID鉴权 String house = loginForm.getHouseId(); IotGwInfo iotGwInfo = new IotGwInfo(); iotGwInfo.setIhouseId(house); List<IotGwInfo> iotGwInfoList = iotGwInfoService.getIotGwInfos(iotGwInfo); if (iotGwInfoList == null || iotGwInfoList.isEmpty()) { LOG.error("上报的houseid:{}下找不到网关", house); return "error"; } redirectURL = redirectURL + "&code=" + loginForm.getHouseId(); LOG.info("登录回调地址:" + redirectURL); return "redirect:" + redirectURL; }
第三部 返回token,我的代码里token值=代码值=单元房ID,因为服务器做的是支持多网关的,一个单元房可以有多个网关
@RequestMapping(value = "/accessToken", method = RequestMethod.POST) public HttpEntity token(HttpServletRequest request) throws OAuthSystemException { OAuthResponse response = null; //构建OAuth请求 try { OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request); String id = oauthRequest.getClientSecret(); LOG.info("clientID:" + id); //if (id != null && id.equals(clientId)) { String token = request.getParameter("code"); //生成OAuth响应 response = OAuthASResponse .tokenResponse(HttpServletResponse.SC_OK) .setAccessToken(token) .setRefreshToken(token) .setParam("expires_in", EXPIRE_TIME) .buildJSONMessage(); //} //根据OAuthResponse生成ResponseEntity return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus())); } catch (OAuthSystemException e) { LOG.error("获取accessToken发生问题", e); response = OAuthASResponse .tokenResponse(HttpServletResponse.SC_OK) .setParam("error", "101") .setParam("error_description", "内部错误") .buildJSONMessage(); return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus())); } catch (OAuthProblemException e) { LOG.error("获取accessToken发生问题", e); response = OAuthASResponse .tokenResponse(HttpServletResponse.SC_OK) .setParam("error", "102") .setParam("error_description", "参数错误") .buildJSONMessage(); return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus())); } }
设备操作这块就是json的了,主要是设备发现,设备查询,设备控制三种功能。
@ApiOperation(value = "设备接口", notes = "设备接口") @RequestMapping(value = "/deviceHandle", method = RequestMethod.POST) public AliDevice deviceHandle(@RequestBody AliDevice aliDeviceReq) { LOG.info("请求数据:" + JSON.toJSONString(aliDeviceReq)); String action = aliDeviceReq.getHeader().getNamespace(); AliDevice resp = new AliDevice(); resp.setHeader(aliDeviceReq.getHeader()); switch (action) { case Constants.Namespace.deviceDiscovery: { aliboxDeviceService.deviceDiscovery(aliDeviceReq.getPayload().getAccessToken(), resp); resp.getHeader().setName(Constants.Name.deviceDiscoveryResp); break; } case Constants.Namespace.deviceControl: { aliboxDeviceService.deviceControl(aliDeviceReq, resp); break; } case Constants.Namespace.deviceQuery: { break; } default: { } } LOG.info("返回数据:" + JSON.toJSONString(resp)); return resp; }
以上是天猫精灵对接
在后台服务器里还需要一个天猫精灵的登录页面,就直接写在后台了,使用thymeleaf,这块就是学习做了,因为对前段不输,就是白板写出了功能。
spring: profiles: shypro thymeleaf: prefix: classpath:/templates/ suffix: .html mode: LEGACYHTML5 encoding: UTF-8 content-type: text/html cache: false
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"></meta> <title>login</title> </head> <body> <h1>login</h1> <div th:object="${loginForm}"> <p th:text="*{houseId}"></p> <p th:text="*{unicode}"></p> </div> <form action="#" th:action="@{/alibox/loginSucess}" th:object="${loginForm}" method="post"> <input type="text" th:field="*{houseId}"/> <input type="text" th:field="*{unicode}" text="${loginForm.unicode}"/> <input type="submit"/> </form> </body> </html>