1 内容介绍
-
登录前端整合
-
微信扫码登录
-
OAuth2
-
微信登录
-
2 登录前端整合
1 api创建login.js文件,定义接口地址
// 登录
submitLogin(userInfo) {
return request({
url: `/educenter/member/login`,
methods: 'post',
data: userInfo
})
},
// 根据token获取用户信息
getLoginUserInfo() {
return request({
url: `/educenter/member/getMemberInfo`,
methods: 'get'
})
}
2 登录页面调用
下载插件:npm install js-cookie
登录和登录成功后首页显示数据实现过程分析
1、调用登录接口,返回token字符串
2、将token放到cookie里面
3、创建前端拦截器
判断cookie里面是否有token,如果有,把token放到header(请求头)
4、根据token调用接口,获取到用户信息,再将返回的用户信息放入cookie
5、首页从cookie中获取到用户信息并显示
// 登录
submitLogin() {
// 1. 调用接口进行登录,返回token字符串
loginApi.submitLoginUser(this.user)
.then(response => {
// 2. 把获取的token放入cookie
// 参数:cookie名称、cookie值、作用范围
cookie.set('guli_token', response.data.data.token, { domain: 'localhost' })
// 3. 创建前端拦截器 utils/request
// 4. 根据token获取用户信息
loginApi.getLoginUserInfo()
.then(response => {
this.loginInfo = response.data.data.userInfo
// 将获取到的用户信息放入cookie
cookie.set('guli_ucenter', this.loginInfo, { domain: 'localhost' })
})
// 跳转页面
window.location.href = '/'
// this.$router.push({ path: '/' })
// 5.页面显示 default.vue
})
}
第3步
// http request 拦截器
service.interceptors.request.use(
config => {
if (cookie.get('guli_token')) {
// 将cookie值放到header中
config.headers['token'] = cookie.get('guli_token')
}
return config
},
err => {
return Promise.reject(err)
})
第5步
created() {
this.showInfo()
},
methods: {
// 创建方法,从cookie中获取用户信息
showInfo() {
const userStr = cookie.get('guli_ucenter')
// 把字符串转为json对象
if (userStr) {
this.loginInfo = JSON.parse(userStr)
}
}
}
问题:跨域
nuxt:get不跨域,post跨域
分析参考:https://juejin.cn/post/6844903712134004743
3 OAuth2
OAuth2是针对特定问题的一种解决方案
主要可以解决两种问题:
-
开放系统间授权
- 方法令牌
-
分布式访问问题(单点登录)
OAuth2解决方案:令牌机制,按照一定规则生成字符串,字符串包含用户信息
只是一个框架,用于授权代理
4 微信扫码登录
准备工作
1、注册开发者资质
不支持个人
微信id、微信密钥
2、申请网站应用名称
3 、要域名地址
1 在service-ucenter配置文件
微信id、密钥、域名地址
2 创建类读取配置文件内容
ConstantWxUtils
3 生成微信扫描二维码
直接请求微信提供的固定地址,向地址拼接参数
@Controller // 只是请求地址,不需要返回数据
@RequestMapping("/api/ucenter/wx")
@CrossOrigin
public class WxApiController {
// 1、生成微信扫描二维码
@GetMapping("login")
public String getWxCode() {
// 固定地址,在后面拼接参数
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 redirect_url = "http://localhost:8160/api/ucenter/wx/callback";
try {
redirect_url = URLEncoder.encode(redirect_url, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String url = String.format(
baseUrl,
ConstantWxUtils.WX_OPEN_APP_ID,
redirect_url,
"atguigu"
);
// 重定向到请求的微信地址
return "redirect:" + url;
}
}
4 获取扫码人信息,添加到数据库
-
扫描后,执行本地的callback方法,在callback获取两个值,state原样传递,code随机唯一的值
-
使用code值,请求微信提供的固定地址,获取到两个值
-
access_token:访问凭证
-
openid:每个微信的唯一标识
-
-
使用access_token、openid,再请求微信提供的固定地址,最终获取扫码人的信息
用到的技术点:
- HttpClient
- JSON转换工具:fastjson gson jackson
引入依赖
<dependencies>
<!--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>
</dependencies>
扫码之后,在首页显示微信信息,比如昵称、头像
之前登录之后显示的用户信息,是首页从cookie中获取的数据
现在也可以按照这样的方式,把扫码后的信息放到cookie,再跳转到首页进行显示
但是,如果把用户信息放到cookie会出问题,因为cookie无法实现跨域访问
最终解决办法:
使用jwt,将微信信息生成一个token字符串,通过路径将token传递到首页面
@GetMapping("callback")
public String callback(String code, String state) {
// 1. 获取code
// 2. 利用code请求微信固定地址,得到access_token openid
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
// 拼接三个参数 appid secret code
String accessTokenUrl = String.format(
baseAccessTokenUrl,
ConstantWxUtils.WX_OPEN_APP_ID,
ConstantWxUtils.WX_OPEN_APP_SECRET,
code
);
try {
// 请求拼接好的地址,得到access_token openid
// 使用HttpClient发送请求
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
// 把accessTokenInfo字符串转换成map结构,根据map里面的key,获取对应的值
// 使用json转换工具: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) { // member是空,表示微信没有注册,需要添加信息到数据库
// 3. 使用access_token、openid,再请求微信提供的固定地址,最终获取扫码人的信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
// 拼接参数
String userInfoUrl = String.format(
baseUserInfoUrl,
access_token,
openid
);
// 发送请求
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,根据微信用户信息,生成token字符串
String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
// 最后回到首页,并通过路径传递token
return "redirect:http://localhost:3000?token=" + jwtToken;
} catch (Exception e) {
throw new GuliException(20001, "登录失败");
}
}
5 在首页显示信息
- 获取首页路径中的token字符串
- 把获取到的token值放入cookie
- 有前端的拦截器,判断cookie中是否有token,如果有,就会把token放入header
- 调用后端接口,根据token值,获取用户信息,最后将获取到的用户信息放入cookie
default.vue
created() {
// 获取路径中的token值
this.token = this.$route.query.token
if (this.token) { // 判断是否有token
this.wxLogin()
}
this.showInfo()
},
methods: {
// 创建方法,从cookie中获取用户信息
showInfo() {
const userStr = cookie.get('guli_ucenter')
// 把字符串转为json对象
if (userStr) {
this.loginInfo = JSON.stringify(userStr)
}
},
// 微信登录显示
wxLogin() {
// token --> cookie
cookie.set('guli_token', this.token, { domain: 'localhost' })
cookie.set('guli_ucenter', '', { domain: 'localhost' })
// 调用接口:根据token获取用户信息
loginApi.getLoginUserInfo()
.then(response => {
this.loginInfo = response.data.data.userInfo
cookie.set('guli_ucenter', this.loginInfo, { domain: 'localhost' })
})
}
}
p207