1. https://open.bot.tmall.com/ 首先了解天猫精灵智能设备的对接文档
2.创建技能什么的都不用讲了,这里主要讲一下服务配置
3.服务配置好以后,我们开始搭建OAuth2授权服务器,这里我选用JAVA,本身自己就是做安卓的,JAVA会比较容易上手
直接贴代码
package com.hjzn.oauth.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.tools.JavaCompiler;
import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.request.OAuthRequest;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.hjzn.oauth.entity.HotelRoom;
import com.hjzn.oauth.entity.Room;
import com.hjzn.oauth.entity.User;
import com.hjzn.oauth.service.RoomService;
import com.hjzn.oauth.service.UserService;
import com.hjzn.oauth.utils.JnaNative;
import com.hjzn.oauth.utils.JnaUtils;
import com.sun.jna.Native;
@Controller
public class OAuthController {
@Autowired
private UserService userService; //登录授权数据层
@Autowired
private RoomService roomService;
private String baseURL = "https://www.xxxxx.com"; //OAuth2授权服务器发布的地址
//private String baseURL = "https://4598907a.ngrok.io";
private String cutURL = baseURL+"/HjznOAuth2/"; //天猫精灵请求授权接口
private String OAuthURL = baseURL+"/HjznOAuth2/responseCode"; //登录成功后将code通过天猫回调地址返回给天猫
private int cutlength = cutURL.length(); //截去参数的时候需要
private String userName; //登录帐号
/**
* 用户登录授权界面
* @param request
* @param response
* @return
* @throws IOException
* @throws OAuthSystemException
*/
@RequestMapping("/userLogin")
public String userlogin(HttpServletRequest request) throws IOException, OAuthSystemException
{
String url = request.getHeader("referer");
//获取到登录帐号
String username = request.getParameter("username");
//获取登录密码
String password = request.getParameter("password");
//登录验证
User user= userService.userLogin(username, password);
if(user!= null)
{
userName = user.getUsername();
log("登录成功!");
String outURL = java.net.URLDecoder.decode(url, "GBK");
log("decode后的地址:"+outURL);
int outlength = outURL.length(); //解密后的请求参数长度
String responseURL = outURL.substring(cutlength, outlength);
log("截取出请求的参数:"+responseURL);
String responseCodeUrl = OAuthURL + responseURL;
log("拼接responseCodeUrl接口:"+responseCodeUrl);
/*
* 拼接完后应该这样子 https://www.xxxxx.com/HjznOAuth2/responseCode?redirect_uri=https://open.bot.tmall.com/oauth/callback?skillId=20690&token=NDExNjU2Nzg1M0FGRUhJTkZEVlE=&client_id=123&response_type=code&state=0.7387369400561126
* */
return "redirect:" + responseCodeUrl; //重定向后就会进入/responseCode
}
else
{
return "redirect:/error.jsp";
}
return "redirect:/error.jsp";
}
/**
* 登录成功将code返回给客户端
* @param model
* @param request
* @return
*/
@RequestMapping("/responseCode")
public String rspCode(HttpServletRequest request){
log("进入responseCode");
try {
//构建OAuth授权请求
OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
String token = oauthRequest.getParam("token");
String state = oauthRequest.getParam("state");
if (oauthRequest.getClientId()!=null&&oauthRequest.getClientId()!="") {
//设置授权码
String authorizationCode = UUID.randomUUID().toString().replace("-", "").substring(0, 18);
log("生成code:"+authorizationCode);
//利用oauth授权请求设置responseType
OAuthASResponse.OAuthAuthorizationResponseBuilder builder=
OAuthASResponse.authorizationResponse(request,HttpServletResponse.SC_FOUND);
//设置授权码
builder.setParam("token", token);
System.out.println(state);
builder.setParam("state", state);
builder.setCode(authorizationCode);
//得到客户端重定向的地址
String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
log("客户端回调地址:"+redirectURI);
//构建响应
OAuthResponse response = builder.location(redirectURI).buildQueryMessage();
String responseUri =response.getLocationUri();
log("responseUri:"+responseUri);
return "redirect:"+responseUri;
}
} catch (Exception e) {
}
return null;
}
/**
* 客户端使用code请求AccessToken
* @param request
* @return
* @throws OAuthSystemException
*/
@RequestMapping(value = "/responseAccessToken",method = RequestMethod.POST)
public HttpEntity token(HttpServletRequest request) throws OAuthSystemException{
log("进入responseAccessToken");
OAuthIssuer oauthIssuerImpl=null;
OAuthResponse response=null;
//构建OAuth请求
try {
OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);
String authCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
String clientSecret = oauthRequest.getClientSecret();
if(clientSecret!=null||clientSecret!=""){
//生成Access Token
oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
final String accessToken = oauthIssuerImpl.accessToken();
final String refreshToken = oauthIssuerImpl.refreshToken();
//生成OAuth响应
response = OAuthASResponse
.tokenResponse(HttpServletResponse.SC_OK)
.setAccessToken(accessToken)
.setRefreshToken(refreshToken)
.setParam("expires_in", "17600000")
.buildJSONMessage();
try {
//这里可以将用户名和token绑定起来 ,在控制设备的时候,可以识别token对应的用户
userService.updateToken(userName, accessToken);
} catch (Exception e) {
log(e.getMessage());
}
}
log("response.getBody:"+response.getBody().toString());
//根据OAuthResponse生成ResponseEntity
return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
} catch (OAuthSystemException e) {
response = OAuthASResponse
.tokenResponse(HttpServletResponse.SC_OK)
.setParam("error", "101")
.setParam("error_description", "内部错误")
.buildJSONMessage();
log("错误"+response.getBody().toString());
return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
} catch (OAuthProblemException e) {
response = OAuthASResponse
.tokenResponse(HttpServletResponse.SC_OK)
.setParam("error", "102")
.setParam("error_description", "参数错误")
.buildJSONMessage();
log("错误"+response.getBody().toString());
log(OAuthURL);
return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
}
}
private void log(String msg){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
System.out.println(df.format(new Date())+"\t"+msg);
}
// 接收天猫精灵发送过来的命令,可以通过json中的namespace来区分命令类型,这里没有进行区分,只做了设备列表假数据的返回
@RequestMapping(value ="/getMessage",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
@ResponseBody
public List<String> getMessage(HttpServletRequest request, HttpServletResponse response,BufferedReader br)
{
log("模拟智能设备进行返回");
//Header部分
JSONObject MerchineList = new JSONObject();
JSONArray jSONArray = new JSONArray();
JSONObject header = new JSONObject();
JSONObject payload = new JSONObject();
List<JSONObject> devices = new ArrayList();
List<JSON> properties = new ArrayList();
List actions = new ArrayList();
JSONObject extentions = new JSONObject();
log(request.getHeaderNames());
Enumeration<?> enum1 = request.getHeaderNames();
while (enum1.hasMoreElements()) {
String key = (String) enum1.nextElement();
String value = request.getHeader(key);
log(key + "\t" + value);
}
//body部分
String inputLine;
String str = "";
try {
while ((inputLine = br.readLine()) != null) {
str += inputLine;
}
br.close();
} catch (IOException e) {
log("IOException: " + e);
}
log("请求参数:" + str);
JSONObject recieveHeader = new JSONObject();
recieveHeader = JSON.parseObject(str);
String str1 = recieveHeader.getString("header");
log("header:" + recieveHeader.getString("header"));
JSONObject recieveMessageId = new JSONObject();
recieveMessageId = JSON.parseObject(str1);
header.put("namespace", "AliGenie.Iot.Device.Discovery");
header.put("name", "DiscoveryDevicesResponse");
header.put("messageId", recieveMessageId.getString("messageId"));
header.put("payLoadVersion", 1);
JSONObject device = new JSONObject();
JSONObject propertie = new JSONObject();
device.put("deviceId", "34ea34cf2e63");
device.put("deviceName", "单孔插座");
device.put("deviceType", "outlet");
device.put("zone", "test");
device.put("brand", "test");
device.put("model", "test");
device.put("icon", "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1531878000&di=c989660f4b827a0049c3b7aec4fe38e1&src=http://img.czvv.com/sell/599adfe4d2f0b1b2f118606f/20170905113247194.jpg");
propertie.put("name", "powerstate");
propertie.put("value", "off");
properties.add(propertie);
device.put("properties", properties);
actions.add("TurnOn");
actions.add("TurnOff");
device.put("actions", actions);
extentions.put("extension1", "tset");
extentions.put("extension2", "test");
device.put("extentions", extentions);
devices.add(device);
payload.put("devices", devices);
MerchineList.put("header", header);
MerchineList.put("payload", payload);
log(MerchineList.toString());
List<String> json = new ArrayList<String>();
json.add(MerchineList.toString());
return json;
}
}
4.授权服务器搭建好后,进入下面第四步,点击测试验证中帐号设置进入你自己写的H5登录授权界面
5.输入帐号密码
6.登陆成功后,你的服务器会自己调用下面的接口,然后生成code传给天猫精灵。
7.天猫精灵携带code,通过下面去请求token
8.返回token到天猫精灵,整个授权流程结束