Oauth2.0 認證協議java
Oauth2.0 應用場景: 微信聯合登陸 受權管理 web
互聯網開放平臺互相調用保證安全spring
微信提供api 給toov5調用 而後就能夠獲取一些微信的信息 好比微信頭像apache
開放平臺有 支付寶 微信 百度等等json
不一樣的開放平臺 對接的oauth2.0協議流程都是相同,無非接口地址不一樣api
Oauth2.0原理 (appId appsecret access_token openId 回調地址 受權地址)tomcat
使用:安全
在微信開放平臺申請對應的appId信息springboot
toov5生成登陸受權鏈接服務器
用於在確認微信登陸以後 跳轉回到回調地址(配置域名權限)
獲取到受權碼 使用受權碼獲取對應的accessToken(調用騰訊藉口權限)
使用accessToken+openId獲取用戶相關信息 (openid 開放userId)
配置 受權訪問鏈接: 經過controller跳轉到 騰訊的鏈接
用戶點擊肯定登陸時候 進入到callback,而且獲取到前面返回的code
拿到code 後面就能夠獲取到相應的 token 和 id了
第一步:用戶贊成受權,獲取code
2 第二步:經過code換取網頁受權access_token
3 第三步:刷新access_token(若是須要)
4 第四步:拉取用戶信息(需scope爲 snsapi_userinfo)
5 附:檢驗受權憑證(access_token)是否有效
maven:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> </parent> <dependencies> <!-- SpringBoot 對lombok 支持 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- SpringBoot web 核心組件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> <!-- SpringBoot 外部tomcat支持 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <!-- springboot-log4j --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency> <!-- springboot-aop 技術 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/commons-lang/commons-lang --> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> </dependencies>
yml:
spring: mvc: view: # 頁面默認前綴目錄 prefix: /WEB-INF/jsp/ # 響應頁面默認後綴 suffix: .jsp appid: wx5c43fde3c9733d9e secret: b8b217126c33a5fb7074927d5e72a81a redirectUri: http://127.0.0.1:8080/callback ### 生成微信受權 官方提供的受權接口 authorizedUrl: https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect ###獲取code後,請求如下連接獲取access_token access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code ###拉取用戶信息(需scope爲 snsapi_userinfo) userinfo: https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
Controller:
import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSONObject; import com.itmayiedu.base.BaseApiService; import com.itmayiedu.utils.HttpClientUtils; import com.itmayiedu.utils.WeiXinUtils; @Controller public class OauthController extends BaseApiService { @Autowired private WeiXinUtils weiXinUtils; private String errorPage = "errorPage"; // 生成受權連接 @RequestMapping("/authorizedUrl") public String authorizedUrl() { System.out.println(weiXinUtils.getAuthorizedUrl()); return "redirect:" + weiXinUtils.getAuthorizedUrl(); //重定向到微信的開放平臺地址 } // 微信受權回調地址 @RequestMapping("/callback") public String callback(String code, HttpServletRequest request) { // 1.使用Code 獲取 access_token String accessTokenUrl = weiXinUtils.getAccessTokenUrl(code); JSONObject resultAccessToken = HttpClientUtils.httpGet(accessTokenUrl); boolean containsKey = resultAccessToken.containsKey("errcode"); if (containsKey) { request.setAttribute("errorMsg", "系統錯誤!"); return errorPage; } // 2.使用access_token獲取用戶信息 String accessToken = resultAccessToken.getString("access_token"); String openid = resultAccessToken.getString("openid"); // 3.拉取用戶信息(需scope爲 snsapi_userinfo) String userInfoUrl = weiXinUtils.getUserInfo(accessToken, openid); JSONObject userInfoResult = HttpClientUtils.httpGet(userInfoUrl); System.out.println("userInfoResult:" + userInfoResult); request.setAttribute("nickname", userInfoResult.getString("nickname")); request.setAttribute("city", userInfoResult.getString("city")); request.setAttribute("headimgurl", userInfoResult.getString("headimgurl")); return "info"; } }
Base:
import org.springframework.stereotype.Component; import com.itmayiedu.utils.Constants; @Component public class BaseApiService { public ResponseBase setResultError(Integer code, String msg) { return setResult(code, msg, null); } // 返回錯誤,能夠傳msg public ResponseBase setResultError(String msg) { return setResult(Constants.HTTP_RES_CODE_500, msg, null); } // 返回成功,能夠傳data值 public ResponseBase setResultSuccessData(Object data) { return setResult(Constants.HTTP_RES_CODE_200, Constants.HTTP_RES_CODE_200_VALUE, data); } public ResponseBase setResultSuccessData(Integer code, Object data) { return setResult(code, Constants.HTTP_RES_CODE_200_VALUE, data); } // 返回成功,沒有data值 public ResponseBase setResultSuccess() { return setResult(Constants.HTTP_RES_CODE_200, Constants.HTTP_RES_CODE_200_VALUE, null); } // 返回成功,沒有data值 public ResponseBase setResultSuccess(String msg) { return setResult(Constants.HTTP_RES_CODE_200, msg, null); } // 通用封裝 public ResponseBase setResult(Integer code, String msg, Object data) { return new ResponseBase(code, msg, data); } }
import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @Getter @Setter @Slf4j public class ResponseBase { private Integer rtnCode; private String msg; private Object data; public ResponseBase() { } public ResponseBase(Integer rtnCode, String msg, Object data) { super(); this.rtnCode = rtnCode; this.msg = msg; this.data = data; } public static void main(String[] args) { ResponseBase responseBase = new ResponseBase(); responseBase.setData("123456"); responseBase.setMsg("success"); responseBase.setRtnCode(200); System.out.println(responseBase.toString()); log.info("itmayiedu..."); } @Override public String toString() { return "ResponseBase [rtnCode=" + rtnCode + ", msg=" + msg + ", data=" + data + "]"; } }
Entity:
public class AppEntity { private long id; private String appId; private String appName; private String appSecret; private String accessToken; private String redirectUri; private int isFlag; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public String getAppName() { return appName; } public void setAppName(String appName) { this.appName = appName; } public String getAppSecret() { return appSecret; } public void setAppSecret(String appSecret) { this.appSecret = appSecret; } public int getIsFlag() { return isFlag; } public void setIsFlag(int isFlag) { this.isFlag = isFlag; } public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public String getRedirectUri() { return redirectUri; } public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } }
import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @Getter @Setter @Slf4j public class ResponseBase { private Integer rtnCode; private String msg; private Object data; public ResponseBase() { } public ResponseBase(Integer rtnCode, String msg, Object data) { super(); this.rtnCode = rtnCode; this.msg = msg; this.data = data; } public static void main(String[] args) { ResponseBase responseBase = new ResponseBase(); responseBase.setData("123456"); responseBase.setMsg("success"); responseBase.setRtnCode(200); System.out.println(responseBase.toString()); log.info("itmayiedu..."); } @Override public String toString() { return "ResponseBase [rtnCode=" + rtnCode + ", msg=" + msg + ", data=" + data + "]"; } }
Util:
public interface Constants { // 響應請求成功 String HTTP_RES_CODE_200_VALUE = "success"; // 系統錯誤 String HTTP_RES_CODE_500_VALUE = "fial"; // 響應請求成功code Integer HTTP_RES_CODE_200 = 200; // 系統錯誤 Integer HTTP_RES_CODE_500 = 500; // 未關聯QQ帳號 Integer HTTP_RES_CODE_201 = 201; // 發送郵件 String MSG_EMAIL = "email"; // 會員token String TOKEN_MEMBER = "TOKEN_MEMBER"; // 支付token String TOKEN_PAY = "TOKEN_pay"; // 支付成功 String PAY_SUCCESS = "success"; // 支付白 String PAY_FAIL = "fail"; // 用戶有效期 90天 Long TOKEN_MEMBER_TIME = (long) (60 * 60 * 24 * 90); int COOKIE_TOKEN_MEMBER_TIME = (60 * 60 * 24 * 90); Long PAY_TOKEN_MEMBER_TIME = (long) (60 * 15); // cookie 會員 totoken 名稱 String COOKIE_MEMBER_TOKEN = "cookie_member_token"; }
import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSONObject; public class HttpClientUtils { private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class); // 日誌記錄 private static RequestConfig requestConfig = null; static { // 設置請求和傳輸超時時間 requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build(); } public static JSONObject httpPost(String url, JSONObject jsonParam) { // post請求返回結果 CloseableHttpClient httpClient = HttpClients.createDefault(); JSONObject jsonResult = null; HttpPost httpPost = new HttpPost(url); // 設置請求和傳輸超時時間 httpPost.setConfig(requestConfig); try { if (null != jsonParam) { // 解決中文亂碼問題 StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8"); entity.setContentEncoding("UTF-8"); entity.setContentType("application/json"); httpPost.setEntity(entity); } CloseableHttpResponse result = httpClient.execute(httpPost); // 請求發送成功,並獲得響應 if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String str = ""; try { // 讀取服務器返回過來的json字符串數據 str = EntityUtils.toString(result.getEntity(), "utf-8"); // 把json字符串轉換成json對象 jsonResult = JSONObject.parseObject(str); } catch (Exception e) { logger.error("post請求提交失敗:" + url, e); } } } catch (IOException e) { logger.error("post請求提交失敗:" + url, e); } finally { httpPost.releaseConnection(); } return jsonResult; } public static JSONObject httpPost(String url, String strParam) { // post請求返回結果 CloseableHttpClient httpClient = HttpClients.createDefault(); JSONObject jsonResult = null; HttpPost httpPost = new HttpPost(url); httpPost.setConfig(requestConfig); try { if (null != strParam) { // 解決中文亂碼問題 StringEntity entity = new StringEntity(strParam, "utf-8"); entity.setContentEncoding("UTF-8"); entity.setContentType("application/x-www-form-urlencoded"); httpPost.setEntity(entity); } CloseableHttpResponse result = httpClient.execute(httpPost); // 請求發送成功,並獲得響應 if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String str = ""; try { // 讀取服務器返回過來的json字符串數據 str = EntityUtils.toString(result.getEntity(), "utf-8"); // 把json字符串轉換成json對象 jsonResult = JSONObject.parseObject(str); } catch (Exception e) { logger.error("post請求提交失敗:" + url, e); } } } catch (IOException e) { logger.error("post請求提交失敗:" + url, e); } finally { httpPost.releaseConnection(); } return jsonResult; } public static JSONObject httpGet(String url) { // get請求返回結果 JSONObject jsonResult = null; CloseableHttpClient client = HttpClients.createDefault(); // 發送get請求 HttpGet request = new HttpGet(url); request.setConfig(requestConfig); try { CloseableHttpResponse response = client.execute(request); // 請求發送成功,並獲得響應 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { // 讀取服務器返回過來的json字符串數據 HttpEntity entity = response.getEntity(); String strResult = EntityUtils.toString(entity, "utf-8"); // 把json字符串轉換成json對象 jsonResult = JSONObject.parseObject(strResult); } else { logger.error("get請求提交失敗:" + url); } } catch (IOException e) { logger.error("get請求提交失敗:" + url, e); } finally { request.releaseConnection(); } return jsonResult; } }
import java.net.URLEncoder; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; @Component public class WeiXinUtils { @Value("${appid}") private String appId; @Value("${secret}") private String secret; @Value("${redirecturi}") private String redirectUri; @Value("${authorizedUrl}") private String authorizedUrl; @Value("${access_token}") private String accessToken; @Value("${userinfo}") private String userinfo; public String getAuthorizedUrl() { return authorizedUrl.replace("APPID", appId).replace("REDIRECT_URI", URLEncoder.encode(redirectUri)); } public String getAccessTokenUrl(String code) { return accessToken.replace("APPID", appId).replace("SECRET", secret).replace("CODE", code); } public String getUserInfo(String accessToken, String openId) { return userinfo.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId); } }
啓動類:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AppOauth { public static void main(String[] args) { SpringApplication.run(AppOauth.class, args); } }