博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
互联网API开放平台安全设计-基于OAuth2.0协议方式
阅读量:2161 次
发布时间:2019-05-01

本文共 16029 字,大约阅读时间需要 53 分钟。

基于OAuth2.0协议方式

什么是OAuth

OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容。

OAuth2.0

对于用户相关的OpenAPI(例如获取用户信息,动态同步,照片,日志,分享等),为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权。

QQ登录OAuth2.0采用OAuth2.0标准协议来进行用户身份验证和获取用户授权,相对于之前的OAuth1.0协议,其认证流程更简单和安全。

 

OAuth2.0总体处理流程

1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

实现微信授权获取信息

微信网页授权地址

https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

1.填写网页授权回调地址权限

2.生成网页授权地址

3.跳转到回调地址获取授权码

http://meitedu.s1.natapp.cc/?code=061yIRgM13IOc41ZQveM1tODgM1yIRge&state=STATE

4. 通过code换取网页授权access_token

https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx5c43fde3c9733d9e&secret=b8b217126c33a5fb7074927d5e72a81a&code=061WfM4E0TABnc2Cv04E02Lb5E0WfM4b&grant_type=authorization_code

4. 拉取用户信息(需scope为 snsapi_userinfo)

4.0.0
com.learn
oauth_web
0.0.1-SNAPSHOT
war
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-tomcat
org.apache.tomcat.embed
tomcat-embed-jasper
org.springframework.boot
spring-boot-starter-log4j
1.3.8.RELEASE
org.springframework.boot
spring-boot-starter-aop
commons-lang
commons-lang
2.6
org.apache.httpcomponents
httpclient
com.alibaba
fastjson
1.2.47
javax.servlet
jstl
taglibs
standard
1.1.2
appid=wx5c43fde3c9733d9esecret=b8b217126c33a5fb7074927d5e72a81aredirectUri=http://127.0.0.1:8080/callbackauthorizedUrl=https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirectaccess_token=https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_codeuserinfo=https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
package com.learn.base;import org.springframework.stereotype.Component;import com.learn.utils.Constants;@Componentpublic 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);	}}
package com.learn.base;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 Integer getRtnCode() {		return rtnCode;	}	public void setRtnCode(Integer rtnCode) {		this.rtnCode = rtnCode;	}	public String getMsg() {		return msg;	}	public void setMsg(String msg) {		this.msg = msg;	}	public Object getData() {		return data;	}	public void setData(Object data) {		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());	}	@Override	public String toString() {		return "ResponseBase [rtnCode=" + rtnCode + ", msg=" + msg + ", data=" + data + "]";	}}
package com.learn.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;	/**	 * @return the id	 */	public long getId() {		return id;	}	/**	 * @param id	 *            the id to set	 */	public void setId(long id) {		this.id = id;	}	/**	 * @return the appId	 */	public String getAppId() {		return appId;	}	/**	 * @param appId	 *            the appId to set	 */	public void setAppId(String appId) {		this.appId = appId;	}	/**	 * @return the appName	 */	public String getAppName() {		return appName;	}	/**	 * @param appName	 *            the appName to set	 */	public void setAppName(String appName) {		this.appName = appName;	}	/**	 * @return the appSecret	 */	public String getAppSecret() {		return appSecret;	}	/**	 * @param appSecret	 *            the appSecret to set	 */	public void setAppSecret(String appSecret) {		this.appSecret = appSecret;	}	/**	 * @return the isFlag	 */	public int getIsFlag() {		return isFlag;	}	/**	 * @param isFlag	 *            the isFlag to set	 */	public void setIsFlag(int isFlag) {		this.isFlag = isFlag;	}	/**	 * @return the accessToken	 */	public String getAccessToken() {		return accessToken;	}	/**	 * @param accessToken	 *            the accessToken to set	 */	public void setAccessToken(String accessToken) {		this.accessToken = accessToken;	}	/**	 * @return the redirectUri	 */	public String getRedirectUri() {		return redirectUri;	}	/**	 * @param redirectUri	 *            the redirectUri to set	 */	public void setRedirectUri(String redirectUri) {		this.redirectUri = redirectUri;	}}
package com.learn.entity;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 Integer getRtnCode() {		return rtnCode;	}	public void setRtnCode(Integer rtnCode) {		this.rtnCode = rtnCode;	}	public String getMsg() {		return msg;	}	public void setMsg(String msg) {		this.msg = msg;	}	public Object getData() {		return data;	}	public void setData(Object data) {		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());	}	@Override	public String toString() {		return "ResponseBase [rtnCode=" + rtnCode + ", msg=" + msg + ", data=" + data + "]";	}}
package com.learn.utils;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";}
package com.learn.utils;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;/** * HttpClient4.3工具类 *  * @author hang.luo */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();	}	/**	 * post请求传输json参数	 * 	 * @param url	 *            url地址	 * @param json	 *            参数	 * @return	 */	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;	}	/**	 * post请求传输String参数 例如:name=Jack&sex=1&type=2	 * Content-type:application/x-www-form-urlencoded	 * 	 * @param url	 *            url地址	 * @param strParam	 *            参数	 * @return	 */	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;	}	/**	 * 发送get请求	 * 	 * @param url	 *            路径	 * @return	 */	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;	}}
package com.learn.utils;import java.net.URLEncoder;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;@Componentpublic 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);	}}
package com.learn.oauth;import javax.servlet.http.HttpServletRequest;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.alibaba.fastjson.JSONObject;import com.learn.base.BaseApiService;import com.learn.utils.HttpClientUtils;import com.learn.utils.WeiXinUtils;@Controllerpublic class OauthController extends BaseApiService {	@Autowired	private WeiXinUtils weiXinUtils;	private String errorPage = "errorPage";	// 生成授权链接	@RequestMapping("/authorizedUrl")	public String authorizedUrl() {		String authorizedUrl = weiXinUtils.getAuthorizedUrl();		System.out.println("authorizedUrl:" + authorizedUrl);		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";	}}
package com.learn;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class AppOauth {	public static void main(String[] args) {		SpringApplication.run(AppOauth.class, args);	}}

准备工作:生成授权链接

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示该链接无法访问”,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限。

https://open.weixin.qq.com/connect/oauth2/authorize?appid= wx5c43fde3c9733d9e &redirect_uri=http://127.0.0.1:8080/callback&response_type=code&scope= snsapi_userinfo &state=STATE#wechat_redirect

1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

5 附:检验授权凭证(access_token)是否有效

转载地址:http://abkzb.baihongyu.com/

你可能感兴趣的文章
【LEETCODE】312-Burst Balloons
查看>>
【LEETCODE】232-Implement Queue using Stacks
查看>>
【LEETCODE】225-Implement Stack using Queues
查看>>
【LEETCODE】155-Min Stack
查看>>
【LEETCODE】20-Valid Parentheses
查看>>
【LEETCODE】290-Word Pattern
查看>>
【LEETCODE】36-Valid Sudoku
查看>>
【LEETCODE】205-Isomorphic Strings
查看>>
【LEETCODE】204-Count Primes
查看>>
【LEETCODE】228-Summary Ranges
查看>>
【LEETCODE】27-Remove Element
查看>>
【LEETCODE】66-Plus One
查看>>
【LEETCODE】26-Remove Duplicates from Sorted Array
查看>>
【LEETCODE】118-Pascal's Triangle
查看>>
【LEETCODE】119-Pascal's Triangle II
查看>>
【LEETCODE】88-Merge Sorted Array
查看>>
【LEETCODE】19-Remove Nth Node From End of List
查看>>
【LEETCODE】125-Valid Palindrome
查看>>
【LEETCODE】28-Implement strStr()
查看>>
【LEETCODE】6-ZigZag Conversion
查看>>