文章目录
登录的本质:服务端验证识别用户信息并返回对应的用户资源。
OAuth2解决方案(token令牌机制的跨应用授权登录和跨服务器单点登录)
现代微服务安全
现代微服务中系统微服务化以及应用的形态和设备类型增多,不能用传统的登录方式
核心的技术不是用户名和密码,而是token,由AuthServer颁发token,用户使用token进行登录,服务端根据秘钥解析token并识别用户信息。
生活场景:QQ账号登录王者荣耀时,需要跳转到QQ授权登录,确认后王者荣耀才可以获取到玩家的QQ账号头像还有好友信息等等.
具体分配第三方应用专属秘钥以及分配token的验证等等则是资源服务器端处理的事务了。
实质上就是加密的用户信息的跨应用授权登录和跨服务器单点登录。
微信登录
扫描之后微信接口返回code(临时票据),拿着code值请求微信固定地址,得到两个值:access_token(访问凭证)和openid(微信唯一标识),你拿着这两个值再去请求微信固定的地址,得到微信扫描人信息(比如昵称,头像等等)
获得微信开放平台授权的准备工作
尚硅谷特殊设置的将微信ID和秘钥的redirect_url回调地址设置为本地的接口形式。
域名服务端程序模拟浏览器将用户微信扫码信息封装为http请求发送到本地接口处理
程序之间通过HttpClient实现http方式的相互请求调用,然后通过Gson将返回的JSON字符串转化为HashMap对象进行数据处理。
九种跨域方式实现原理(完整版)
需要跨域功能是因为前端项目端口和后端项目端口不一样属于跨域类型
cookie不能实现跨域所以前后端分离的项目中不能通过cookie传值:因为前端项目端口和后端项目端口不一样属于跨域类型
前端
域名端服务器是尚硅谷为教学特殊设置的,可以将用户信息转发到和域名路径相同的本地接口中处理,让学员体验代码操作,实际上本地接口的代码是部署在域名服务端直接 处理用户信息的。
域名:
配置文件
配置微信扫码后平台的回调redirect_url为本地接口方法,触发方法从而实现微信信息获取.
# 微信开放平台 appid
wx.open.app_id=wxed9954c01bb89b47
# 微信开放平台 appsecret
wx.open.app_secret=a7482517235173ddb4083788de60b90e
# 微信开放平台 重定向url域名,域名端服务器处理信息返回到本地接口处理,实际开发中域名端服务器就类比第三方服务端
wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback
添加依赖
程序之间通过HttpClient实现http方式的相互请求调用,然后通过Gson将返回的JSON字符串转化为HashMap对象进行数据处理。
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
API方法(URL形式)
由微信认证的appid获得用户授权code凭证
通过微信平台认证的APPID访问微信开放平台固定URL地址,微信开放平台端发布一个二维码,用户扫描授权后,平台就根据拼接参数重定向到本地并传递code认证
第三方应用请求微信开放平台的方式(URL)
return "redirect"会实现浏览器地址栏的重定向。
//1 生成微信扫描二维码
@GetMapping("login")
public String getWxCode() {
//固定地址,后面拼接参数
// String url = "https://open.weixin.qq.com/" +
// "connect/qrconnect?appid="+ ConstantWxUtils.WX_OPEN_APP_ID+"&response_type=code";
// 微信开放平台授权baseUrl %s相当于?代表占位符
String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
"?appid=%s" +
"&redirect_uri=%s" +
"&response_type=code" +
"&scope=snsapi_login" +
"&state=%s" +
"#wechat_redirect";
//对redirect_url进行URLEncoder编码
String redirectUrl = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
try {
redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
System.out.println(redirectUrl);
}catch(Exception e) {
}
//设置%s里面值
String url = String.format(
baseUrl,
ConstantWxUtils.WX_OPEN_APP_ID,
redirectUrl,
"QLUGCL"
);
System.out.println(url);
//重定向到请求微信地址里面
return "redirect:"+url;
// http://localhost:8160/api/ucenter/wx/callback?code=071cMSkl2ruEW84fRNml2Xq0yS0cMSk7&state=QLUGCL
}
由微信认证的APPID和秘钥还有用户授权的code认证获得access_token和openid(微信用户唯一标识符)
最后根据access_token和openid获得用户信息(昵称和头像等等)
//2 获取扫描人信息,添加数据
@GetMapping("callback")
public String callback(String code, String state) {
try {
//1 获取code值,临时票据,类似于验证码
//2 拿着code请求 微信固定的地址,得到两个值 accsess_token 和 openid
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
//拼接三个参数 :id 秘钥 和 code值
String accessTokenUrl = String.format(
baseAccessTokenUrl,
ConstantWxUtils.WX_OPEN_APP_ID,
ConstantWxUtils.WX_OPEN_APP_SECRET,
code
);
//请求这个拼接好的地址,得到返回两个值 accsess_token 和 openid
//使用httpclient发送请求,得到返回结果
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
//从accessTokenInfo字符串获取出来两个值 accsess_token 和 openid
//把accessTokenInfo字符串转换map集合,根据map里面key获取对应值
//使用json转换工具 Gson:嫁入Google豪门的Gson
Gson gson = new Gson();
HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
String access_token = (String)mapAccessToken.get("access_token");
String openid = (String)mapAccessToken.get("openid");
//把扫描人信息添加数据库里面
//判断数据表里面是否存在相同微信信息,根据openid判断
UcenterMember member = memberService.getOpenIdMember(openid);
if(member == null) {//memeber是空,表没有相同微信数据,进行添加
//3 拿着得到accsess_token 和 openid,再去请求微信提供固定的地址,获取到扫描人信息
//访问微信的资源服务器,获取用户信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
//拼接两个参数
String userInfoUrl = String.format(
baseUserInfoUrl,
access_token,
openid
);
//Httpclient发送请求
String userInfo = HttpClientUtils.get(userInfoUrl);
//获取返回userinfo字符串扫描人信息
HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
String nickname = (String)userInfoMap.get("nickname");//昵称
String headimgurl = (String)userInfoMap.get("headimgurl");//头像
member = new UcenterMember();
member.setOpenid(openid);
member.setNickname(nickname);
member.setAvatar(headimgurl);
memberService.save(member);
}
//使用jwt根据member对象生成token字符串
String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
//最后:返回首页面,通过路径传递token字符串
return "redirect:http://localhost:3000?token="+jwtToken;
}catch(Exception e) {
throw new GCLException(20001,"登录失败");
}
}
前端提取token
总结
程序之间通过HttpClient实现http方式的相互请求调用,然后通过Gson将返回的JSON字符串转化为HashMap对象进行数据处理。
简单来说
- 首先第三方应用需要通过微信开放平台的审核还有认证,确保用途合法,获取第三方专属ID和秘钥等信息
- 接下来就是访问微信平台固定地址(URL),根据微信认可的ID在平台端获取微信二维码(微信平台提供和显示二维码)
- 用户扫描二维码授权后平台会根据服务端访问URL的拼接参数确定接下来的服务(用户扫码授权后的信息处理也是微信平台提供)
- 直接拉起第三方应用或者将用户信息凭证通过HttpClient技术封装转发给第三方接口的域名处理(redirect_url)
- 上述代码的回调地址为尚硅谷为教学特殊设置的秘钥和ID匹配本地接口,微信平台将用户信息转发到路径相同的本地接口中处理,让学员体验代码操作,实际上本地接口的代码是部署在域名服务端直接 处理用户信息的。
- 若是redirect则微信平台会返回一个code凭证,然后根据code凭证,ID和秘钥再次封装httpclient请求微信开放平台
- 返回的access_token和openid,然后根据返回的token和id再次HttpClient访问微信平台得到用户信息
- 最后可以将用户信息转为token字符串传递给前端进行显示了。