課程計划
- 1、SSO注冊功能實現
- 2、SSO登錄功能實現
- 3、通過token獲得用戶信息
- 4、ajax跨域請求解決方案--jsonp
1、服務接口實現
SSO系統就是解決分布式環境下登錄問題的,本質上是解決分布式環境下session共享問題。
1.1、檢查數據是否可用接口開發
檢查數據是否可用作為注冊功能的輔助。

1.1.1、功能分析
請求的url:/user/check/{param}/{type}
參數:從url中取參數
1、String param(要校驗的數據)
2、Integer type(校驗的數據類型)
響應的數據:json數據。TaotaoResult,封裝的數據校驗的結果為true:表示成功,數據可用,false:失敗,數據不可用。
業務邏輯:
1、從tb_user表中查詢數據。
2、查詢條件根據傳遞過來的參數動態生成。
3、判斷查詢結果,如果查詢到數據就返回false。
4、如果沒有查詢到數據就返回true。
5、使用TaotaoResult包裝,並返回。
1.1.2、Dao
從tb_user表查詢。屬於單表查詢,可以使用逆向工程生成的代碼。
1.1.3、Service
先在taotao-sso-interface中定義接口UserRegisterService,
再在taotao-sso-service中寫實現類。
參數:
1、要校驗的數據:String param
2、數據類型:Integer type(1、2、3分別代表username、phone、email)
返回值:TaotaoResult
在taotao-sso-interface創建接口
/**
* 用戶注冊管理接口
* @author chenmingjun
* @date 2018年12月3日 上午9:47:29
* @version V1.0
*/
public interface UserRegisterService {
/**
* 檢查APP傳過來的數據是否可用
* @param param 要校驗的數據
* @param type 校驗的數據類型
* @return
*/
TaotaoResult checkData(String param, Integer type);
}
在taotao-sso-service創建實現類
@Autowired
private TbUserMapper tbUserMapper;
@Override
public TaotaoResult checkData(String param, Integer type) {
// 1、從tb_user表中查詢數據
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
// 2、查詢條件根據傳遞過來的參數動態生成
// 1、2、3分別代表username、phone、email
if (type == 1) {
criteria.andUsernameEqualTo(param);
} else if (type == 2) {
criteria.andPhoneEqualTo(param);
} else if (type == 3) {
criteria.andEmailEqualTo(param);
} else {
return TaotaoResult.build(400, "傳遞過來的是非法的參數");
}
// 執行查詢
List<TbUser> list = tbUserMapper.selectByExample(example);
// 3、判斷查詢結果,如果查詢到數據就返回false
if (list == null || list.size() == 0) {
// 4、如果沒有查詢到數據就返回true
return TaotaoResult.ok(true);
}
// 5、使用TaotaoResult包裝,並返回
return TaotaoResult.ok(false);
}
1.1.4、發布服務
先在taotao-sso-service工程中的pom.xml文件中配置對taotao-sso-interface的依賴,因為服務層發布服務要通過該接口,
再在taotao-sso-service工程中的applicationContext-service.xml文件中發布服務:

1.1.5、引用服務
需要在taotao-sso-web中實現。
先在taotao-sso-web工程中的pom.xml文件中配置對taotao-sso-interface的依賴,表現層調用服務要通過該接口,
在taotao-sso-web工程中的springmvc.xml文件中引用服務:

1.1.6、Controller
請求的url:/user/check/{param}/{type}
參數:從url中取參數
1、String param(要校驗的數據)
2、Integer type(校驗的數據類型)
請求的方法:get。
響應的數據:json數據。TaotaoResult,封裝的數據校驗的結果,true:成功;false:失敗。
/**
* 用戶處理Controller
* @author chenmingjun
* @date 2018年12月3日 上午10:31:38
* @version V1.0
*/
@Controller
public class UserController {
@Autowired
private UserRegisterService userRegisterService;
@RequestMapping(value="/user/check/{param}/{type}", method=RequestMethod.GET)
@ResponseBody
public TaotaoResult checkData(@PathVariable String param, @PathVariable Integer type) {
TaotaoResult result = userRegisterService.checkData(param, type);
return result;
}
}
1.1.7、測試
get請求好測試,直接在瀏覽器中輸入URL即可。
訪問地址:http://localhost:8088/user/check/zhangsan/1
瀏覽器報404錯誤,原因是:我們web.xml中配置的是攔截以“.html”為后綴的請求。
我們修改訪問地址:http://localhost:8088/user/check/zhangsan/1.html
此時瀏覽器報406錯誤。原因如下圖:

而且如果我們在請求后面加上“.html”的話,等於我們修改了接口開發文檔,這是不行的。
正確的做法是要攔截不帶后綴的請求,我們使用“/”即攔截所有請求,如下圖所示:

下面我們詳解406錯誤的形成原因?
答:當我們瀏覽器出現406錯誤時,90%的原因是因為沒有導入jackson-core-2.4.2.jar這個包。10%的原因是我們請求的URL后綴是“.html”。為什么呢?
原因是:在springMVC中使用注解@ResponseBody,springMVC認為對於后綴是“.html”的URL請求,服務端返回的應該也是一個html頁面。但是如果服務端返回的是一個java對象的話,那么瀏覽器不能將一個java對象轉換成一個html對象,即就會報406錯誤。(
這是一個大坑!
)
1.2、用戶注冊接口開發
1.2.1、功能分析

請求的url:/user/register
參數:表單的數據:username、password、phone、email
返回值:json數據。TaotaoResult。
接收參數:使用TbUser對象接收。
請求的方法:post
業務邏輯:
1、使用TbUser接收提交的請求。
2、補全TbUser其他屬性。
3、
密碼要進行MD5加密
。
4、把用戶信息插入到數據庫中。
5、返回TaotaoResult.ok()。
1.2.2、Dao
可以使用逆向工程生成的代碼。
1.2.3、Service
在taotao-sso-interface中定義接口UserRegisterService已經定義好了,我們直接添加方法即可。
再在taotao-sso-service中寫實現類,我們已經定義好了,直接實現方法即可。
參數:TbUser
返回值:TaotaoResult
在taotao-sso-interface創建接口
/**
* 用戶注冊
* @param tbUser 用戶表
* @return
*/
TaotaoResult register(TbUser tbUser);
}
在taotao-sso-service創建實現類
@Override
public TaotaoResult register(TbUser tbUser) {
// 1、校驗用戶名和密碼不能為空
if (StringUtils.isEmpty(tbUser.getUsername())) {
return TaotaoResult.build(400, "注冊失敗,用戶名不能為空");
}
if (StringUtils.isEmpty(tbUser.getPassword())) {
return TaotaoResult.build(400, "注冊失敗,密碼不能為空");
}
// 2、校驗數據的可用性
// 2.1 、校驗username是否可用
TaotaoResult checkData = checkData(tbUser.getUsername(), 1);
if (!(boolean) checkData.getData()) { // 說明username不可用,返回400
return TaotaoResult.build(400, "用戶名已被使用");
}
// 2.2、校驗phone是否可用
if (StringUtils.isNotBlank(tbUser.getPhone())) { // 說明phone不為空
if (!(boolean) checkData.getData()) { // 說明phone不可用,返回400
return TaotaoResult.build(400, "手機號已被使用");
}
}
// 2.3、校驗email是否可用
if (StringUtils.isNotBlank(tbUser.getEmail())) { // 說明email不為空
if (!(boolean) checkData.getData()) { // 說明email不可用,返回400
return TaotaoResult.build(400, "郵箱已被使用");
}
}
// 補全TbUser其他屬性
tbUser.setCreated(new Date());
tbUser.setUpdated(tbUser.getCreated());
// 密碼的MD5加密處理
String password = tbUser.getPassword();
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
tbUser.setPassword(md5Password);
// 把用戶信息插入到數據庫中
tbUserMapper.insertSelective(tbUser);
return TaotaoResult.ok();
}
1.2.4、發布服務
在taotao-sso-service工程中applicationContext-service.xml文件中發布服務,上面“1.1.4”中已經發布過了。不在贅圖!
1.2.5、引用服務
在taotao-sso-web工程中的springmvc.xml文件中引用服務,上面“1.1.5”中已經引用過了。不在贅圖!
1.2.6、Controller
請求的url:/user/register
參數:表單的數據:username、password、phone、email
返回值:json數據。TaotaoResult。
接收參數:使用TbUser對象接收。
請求的方法:post
@RequestMapping(value="/user/register", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult register(TbUser tbUser) {
TaotaoResult result = userRegisterService.register(tbUser);
return result;
}
1.2.7、測試
post請求不好測試,需要我們新建表單,太麻煩了,我們可以使用一個工具。如下:

可以使用
restclient-ui-3.5-jar-with-dependencies.jar
測試接口。
點擊編輯按鈕,填寫表單提交的content-type:application/x-www-form-urlencoded

點擊插入參數按鈕,填寫參數后,點擊生成。

點擊提交按鈕,測試開始。
1.3、用戶登錄接口開發
1.3.1、功能分析

請求的url:/user/login
請求的方法:POST
參數:username、password,表單提交的數據。可以使用方法的形參接收。
返回值:json數據,使用TaotaoResult包含一個token。
業務邏輯:
登錄的業務流程:

登錄的處理流程:
1、登錄頁面提交用戶名密碼。
2、登錄成功后生成token。token相當於原來的jsessionid,字符串,可以使用uuid。
3、把用戶信息保存到redis。key就是token,value就是TbUser對象轉換成的json字符串。
4、使用String類型保存session信息。可以使用
“前綴:token”
為key。
5、設置key的過期時間。模擬session的過期時間。一般半個小時。
6、把token寫入cookie中。
7、cookie需要跨域。例如:www.taotao.com\sso.taotao.com\order.taotao.com,可以使用工具類。
8、cookie的有效期。關閉瀏覽器失效。
9、登錄成功。
1.3.2、Dao
查詢tb_user表。單表查詢。可以使用逆向工程生成的代碼。
1.3.3、Service
參數:
1、用戶名:String username
2、密碼:String password
返回值:TaotaoResult,包裝token。
業務邏輯:
1、判斷用戶名和密碼是否正確。
2、登錄成功后生成token。token相當於原來的jsessionid,字符串,可以使用uuid。
3、把用戶信息保存到redis。key就是token,value就是TbUser對象轉換成的json串。
4、使用String類型保存session信息。可以使用“前綴:token”為key。
5、設置key的過期時間。模擬session的過期時間。一般半個小時。
6、返回TaotaoResult包裝token。
部分代碼:需要設置加載屬性文件。
在taotao-sso-interface創建接口
/**
* 用戶登錄管理接口
* @author chenmingjun
* @date 2018年12月3日 下午6:04:21
* @version V1.0
*/
public interface UserLoginService {
/**
* 根據用戶名和密碼進行登錄,生成token作為key,user作為value
* @param username
* @param password
* @return
*/
TaotaoResult login(String username, String password);
}
在taotao-sso-service創建實現類
@Service
public class UserLoginServiceImpl implements UserLoginService {
@Autowired
private TbUserMapper tbUserMapper;
// 注入jedisClient對象
@Autowired
private JedisClient jedisClient;
@Value("${USER_SESSION}")
private String USER_SESSION;
@Value("${SESSION_EXPIRE}")
private Integer SESSION_EXPIRE;
@Override
public TaotaoResult login(String username, String password) {
// 1、判斷用戶名和密碼是否正確。
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
// 查詢用戶信息,校驗用戶名
List<TbUser> list = tbUserMapper.selectByExample(example);
if (list == null || list.size() == 0) { // 說明沒有查詢到用戶信息,即用戶名輸入錯誤
return TaotaoResult.build(400, "用戶名或密碼錯誤");
}
// 取出用戶信息,校驗密碼
TbUser tbUser = list.get(0);
if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(tbUser.getPassword())) { // 說明密碼不正確
return TaotaoResult.build(400, "用戶名或密碼錯誤");
}
// 2、登錄成功后生成token。token相當於原來的jsessionid,字符串,可以使用uuid。
String token = UUID.randomUUID().toString();
// 我們密碼就不要存到redis中了,所以要清空密碼
tbUser.setPassword(null);
// 3、把用戶信息保存到redis。key就是token,value就是TbUser對象轉換成的json串。
// 4、使用String類型保存session信息。可以使用“前綴:token”為key。
jedisClient.set(USER_SESSION + ":" + token, JsonUtils.objectToJson(tbUser));
// 5、設置key的過期時間。模擬session的過期時間。一般半個小時。
jedisClient.expire(USER_SESSION + ":" + token, SESSION_EXPIRE);
// 6、返回TaotaoResult包裝token。
return TaotaoResult.ok(token);
}
}
1.3.4、發布服務
在taotao-sso-service工程中applicationContext-service.xml文件中發布服務:

在taotao-sso-service工程中applicationContext-dao.xml文件中加載配置文件:

配置文件內容如下:

1.3.5、引用服務
在taotao-sso-web工程中的springmvc.xml文件中引用服務:

1.3.6、Controller
請求的url:/user/login
請求的方法:POST
參數:username、password,表單提交的數據。
因為只有兩個參數,所以不用使用pojo來接收,可以使用方法的形參接收就可以。
從返回結果中取出token,寫入cookie。需要使用HttpServletRequest、HttpServletResponse
返回值:json數據,使用TaotaoResult包含一個token。
業務邏輯:
1、接收表單提交的兩個參數。
2、調用Service層的方法進行登錄。
3、從返回結果中取token,寫入cookie。注意:cookie要跨域。
cookie的二級域名跨域需要進行設置
:
1)setDomain(),設置一級域名:
.itcast.cn
.taotao.com
.taotao.com.cn
2)setPath(),設置為“/”
可以使用工具類。工具類放到taotao-common工程中。

需要加入servlet-api的依賴包:在common項目中的pom.xml中,加入依賴:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
注意:scope
的值是provided
,表示該jar包在運行時使用
、編譯時使用
、測試時用
,但是打包的時候不用
,因為該jar包web容器tomcat會提供,如果打包的時候使用該jar包,會出現沖突
。
4、響應數據。json數據。TaotaoResult,其中包含token。
@RequestMapping(value="/user/login", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult login(String username, String password, HttpServletRequest request, HttpServletResponse response) {
// 1、接收表單提交的兩個參數。
// 2、調用Service層的方法進行登錄。
TaotaoResult result = userLoginService.login(username, password);
// 3、從返回結果中取出token,寫入cookie。注意:cookie要跨域。
if (result.getStatus() == 200) {
String token = result.getData().toString(); // 從返回結果中取出token
CookieUtils.setCookie(request, response, COOKIE_TOKEN_KEY, token);
}
return result;
}
在taotao-sso-web工程中springmvc.xml文件中加載配置文件:

配置文件內容如下:

1.3.7、測試
使用restclient-ui-3.5-jar-with-dependencies.jar
測試接口,查看Body;然后查看redis服務器中的key。
1.4、通過token查詢用戶信息接口開發
1.4.1、功能分析

請求的url:/user/token/{token}
參數:String token(需要從url中取)
返回值:json數據。使用TaotaoResult包裝Tbuser對象。
業務邏輯:
1、從url中取參數。
2、根據token查詢redis。
3、如果查詢不到數據,則返回用戶已經過期。
4、如果查詢到數據,則說明用戶已經登錄。
5、需要重置key的過期時間。
6、把json數據轉換成TbUser對象,然后使用TaotaoResult包裝並返回。
1.4.2、Dao
使用JedisClient對象進行查詢。
1.4.3、Service
參數:String token
返回值:TaotaoResult
在taotao-sso-interface創建接口
/**
* 根據token從redis中查詢用戶信息
* @param token
* @return
*/
TaotaoResult getUserByToken(String token);
在taotao-sso-service創建實現類
@Override
public TaotaoResult getUserByToken(String token) {
// 2、根據token查詢redis。
String jsonString = jedisClient.get(USER_SESSION + ":" + token);
if (StringUtils.isBlank(jsonString)) {
// 3、如果查詢不到數據,則返回用戶已經過期。
return TaotaoResult.build(400, "用戶登錄狀態已過期,請重新登錄");
}
// 4、如果查詢到數據,則說明用戶已經登錄。
// 5、需要重置key(USER_SESSION)的過期時間。
jedisClient.expire(USER_SESSION + ":" + token, SESSION_EXPIRE);
// 6、把json數據轉換成TbUser對象,然后使用TaotaoResult包裝並返回。
TbUser tbUser = JsonUtils.jsonToPojo(jsonString, TbUser.class);
return TaotaoResult.ok(tbUser);
// return TaotaoResult.ok(json);
}
注意:如果返回的是:return TaotaoResult.ok(json);
那么返回的json串中會有轉義字符,如下:
{
"status": 200
"msg": "OK"
"data": "{\"id\":1,\"username\":\"zhangsan\",\"password\":null,\"phone\":\"15800807944\",\"email\":\"420840806@qq.com\",\"created\":1414119176000,\"updated\":1414119179000}"
}
這跟我們接口開發文檔中的格式不一樣,接口開發文檔中的格式如下:
{
"status": 200
"msg": "OK"
"data": {"id":1,"username":"zhangzhijun","password":null,"phone":"15800807944","email":"420840806@qq.com","created":1414119176000,"updated":1414119179000}
}
1.4.4、發布服務
在taotao-sso-service工程中applicationContext-service.xml文件中發布服務,上面“1.3.4”中已經發布過了。不在贅圖!
1.4.5、引用服務
在taotao-sso-web工程中的springmvc.xml文件中引用服務,上面“1.3.5”中已經引用過了。不在贅圖!
1.4.6、Controller
請求的url:/user/token/{token}
參數:String token (需要從url中取)
返回值:json數據。使用TaotaoResult包裝Tbuser對象。
@RequestMapping(value="/user/token/{token}", method=RequestMethod.GET)
@ResponseBody
public TaotaoResult getUserByToken(@PathVariable String token) {
TaotaoResult result = userLoginService.getUserByToken(token);
return result;
}
1.4.7、測試
get請求好測試,直接在瀏覽器中輸入URL即可。
訪問地址:http://localhost:8088/user/token/cd3c4925-c780-4e15-b8c2-ca9dc764fe47
1.5、安全退出接口開發
1.5.1、功能分析

需要根據token刪除redis中對應的key。
從接口文檔可知
url:user/logout/{token}
參數:token
返回值:由TaotaoResule封裝的信息"ok"。
1.5.2、Dao
直接使用RedisClient訪問redis。
1.5.3、Service
在taotao-sso-interface創建接口
/**
* 根據token從redis刪除對應的key
* @param token
* @return
*/
TaotaoResult logout(String token);
在taotao-sso-service創建實現類
@Override
public TaotaoResult logout(String token) {
jedisClient.expire(USER_SESSION + ":" + token, 0);
return TaotaoResult.ok();
}
1.5.4、發布服務
在taotao-sso-service工程中applicationContext-service.xml文件中發布服務,上面“1.3.4”中已經發布過了。不在贅圖!
1.5.5、引用服務
在taotao-sso-web工程中的springmvc.xml文件中引用服務,上面“1.3.5”中已經引用過了。不在贅圖!
1.5.6、Controller
url:user/logout/{token}
參數:token
@RequestMapping(value="/user/logout/{token}", method=RequestMethod.GET)
@ResponseBody
public TaotaoResult logout(@PathVariable String token) {
TaotaoResult result = userLoginService.logout(token);
return result;
}
1.5.7、測試
安裝taotao-sso,啟動taotao-sso、taotao-sso-web。
從redis中找一個存在的token:70ae13a6-87bb-4e3a-b713-35d7979c4bd8
使用RESETClirnt測試訪問,刪除token:70ae13a6-87bb-4e3a-b713-35d7979c4bd8 的用戶
提示刪除成功!
2、實現SSO系統的登錄注冊功能
2.1、展示登錄及注冊頁面及首頁超鏈接修改
第一步:加入靜態文件及JSP頁面

第二步:在taotao-sso-web的springmvc.xml文件中配置資源映射標簽,即不攔截靜態資源。

第三步:點擊門戶首頁登錄按鈕,瀏覽器URL為:
http://localhost:8084/page/login,報錯:

第四步:點擊門戶首頁的免費注冊按鈕,瀏覽器的URL為:
http://localhost:8084/page/register,報錯:

由此我們發現,其實登錄注冊的URL非常類似:
http://localhost:8084/page/register
http://localhost:8084/page/login
所以通過
/page/{page}
的方式請求,通過
URL模板映射
,使用
@PathVariable注解
即可接收請求,轉發jsp頁面,代碼如下:
使用rsetful,跳轉不同頁面

第五步:修改端口號為訪問登錄注冊的端口號為
8088

測試:通過。
2.2、注冊功能實現
/taotao-sso-web/src/main/webapp/WEB-INF/jsp/register.jsp分析:

提交之前檢查:

注冊,提交表單:

分析得出,此時的登錄功能應該是可以使用了。
2.3、登錄功能實現
/taotao-sso-web/src/main/webapp/WEB-INF/jsp/login.jsp分析:

文檔加載時,調用方法,一旦點擊,則提交表單:

表單提交:

分析得出,登錄功能也是可以使用的。
3、門戶首頁展示用戶名
3.1、首頁展示用戶名分析
1、在taotao-sso-web工程中,當用戶登錄成功后,在cookie中有token信息。
2、在taotao-portal-web工程中,從cookie中取出token,攜帶token發送格式為jsonp的請求,根據token從taotao-sso-web工程中查詢用戶信息。
3、把從taotao-sso-web工程中查詢到的用戶名展示到首頁taotao-portal-web工程中。
方案一:在Controller中取cookie中的token數據,調用sso服務查詢用戶信息。
缺點:由於淘淘商城首頁footer.jsp,在每個系統中都有,可以在每一個系統的footer.jsp中寫一個ajax發起請求調用當前系統的Controller,設置模型數據,然后展示數據。麻煩!
方案二:當頁面加載完成后使用js取cookie中token的數據,使用ajax請求查詢用戶信息的JSON數據。只需要在頁面實現一次即可。
乍一看方案一與方案二是一樣的,其實不是,方案一需要在每一個系統都編寫Controller,方案二只需要在taotao-sso-web編寫一個Controller即可。而且方案一是立即可行的,但是方案二的服務接口在sso系統中。sso.taotao.com(localhost:8088),在首頁顯示用戶名稱,首頁的域名是www.taotao.com(localhost:8082),使用ajax請求跨域了。
什么是跨域:
1、域名不同。
2、域名相同端口不同。
例如:
www.taotao.com --> 請求 www.taobao.com 也是跨域
www.taotao.com --> 請求 sso.taotao.com 也是跨域
www.taotao.com:8080 --> www.taotao.com:8088 也是跨域
localhost:8080 --> localhost:8088 也是跨域
www.taotao.com --> www.taotao.com 不是跨域
只有域名和端口完全一樣才不是跨域。js不可以跨域請求JSON數據
。
解決js的跨域問題可以使用jsonp。jsonp
不是新技術是跨域的解決方案
。使用js的特性繞過跨域請求,特性:js可以跨域加載js文件
。
3.2、jsonp原理
舉個非常常見的例子,我們在html頭部一般都會引入很多js,甚至我們直接引用在線的js,比如我們引用官方網站的jQuery路徑加載進來也是可以的。jQuery的官方域名與我們的工程所在的域名肯定是不一樣的,但是不影響使用,這就是我們所說的js可以跨域請求js文件!
即:ajax無法跨域請求別的url,我們可以使用ajax跨域加載js文件。

http://localhost:8088/user/token/4ffd07a2-1f92-4601-94ff-2ab763931018?callback=fun
8088做處理:查詢到JSON數據,拼接成fun({"id":1});
8082瀏覽器加載fun({"id":1});
調用fun方法,里面參數就是JSON數據。做相關的處理。
更加詳細的解釋:
參考鏈接:https://blog.csdn.net/pdsu161530247/article/details/82189866
3.3、jsonp實現
3.3.1、客戶端:使用ajax自帶的callback函數
使用jQuery。
在/taotao-portal-web/src/main/webapp/js/taotao.js中:
使用ajax的dataType : "jsonp",將success : function當做回調函數。
客戶端是taotao-portal-web工程:

taotao.js代碼如下:

3.3.2、服務端:springmvc支持jsonp的兩種實現方法
ajax設置的callback函數,我們在后端就需要封裝一個callback(jsondata),讓前端將jsondata作為參數調用。
方法一:springmvc4.1之前的實現方法
服務端是taotao-sso-web工程:

方法二:springmvc4.1之后的實現方法
springmvc4.1以后,下面兩行代碼會自動幫我們封裝callback(jsondata)
服務端是taotao-sso-web工程:
