Oauth2.0认证原理
Oauth2.0 认证协议
Oauth2.0 应用场景: 微信联合登录 授权管理
互联网开放平台互相调用保证安全
微信提供api 给toov5调用 然后就可以获取一些微信的信息 比如微信头像
开放平台有 支付宝 微信 百度等等
不同的开放平台 对接的oauth2.0协议流程都是相同,无非接口地址不同
Oauth2.0原理 (appId appsecret access_token openId 回调地址 授权地址)
使用:
在微信开放平台申请对应的appId信息
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); } }