实现接入微信登录,代码详细

第三方授权登录和支付

1.1 整合微信登录

1.1.1 文档地址

微信文档地址

1.1.2 生成微信二维码
  • application.properties 配置信息
# appId
wechat.appId=wx12411231
# 密钥
wechat.appSecret=feageasgeaege
# 重定向地址,其实微信后台配置的重定向地址,可以随便改动,只要能够访问与以下配置项的域名一致即可。
# 假如你的微信后台配置的域名为:test.com, 配置文件如下配置,后面的地址为controller的路径
wechat.redirectUrl=http://test.com/api/ucenter/wx/callback
  • 封装微信配置类
package com.song.cms.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * wx prop settings
 */
@Data
@Component
@Configuration
@ConfigurationProperties(prefix = "wechat")
public class WechatProperties {

    private String appId;
    private String appSecret;
    private String redirectUrl;

}
  • controller
@CrossOrigin
@Controller
@RequestMapping("/api/ucenter/wx")
@Slf4j
public class WxLoginController {

    @Autowired
    private LoginService loginService;

    /**
     * 生成微信二维码
     */
    @GetMapping("login")
    public String buildQrCode() throws UnsupportedEncodingException {
        String url = loginService.buildQrCode();
        return String.format("redirect:%s", url);
    }
}
  • service
@Autowired
private WechatProperties wechatProperties;

/**
  * 生成微信二维码
  */
@Override
public String buildQrCode() throws UnsupportedEncodingException {
    String baseUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code" +
        "&scope=snsapi_login&state=%s#wechat_redirect";
    String redirectUrl = URLEncoder.encode(wechatProperties.getRedirectUrl(), "utf-8");
    return String.format(baseUrl, wechatProperties.getAppId(), redirectUrl, RandomStringUtils.randomAlphanumeric(6));
}
1.1.3 微信回调地址
  • 引入okhttp3, gson
<properties>
    <okhttp.version>4.4.0okhttp.version>
    <gson.version>2.8.6gson.version>
properties>


<dependency>
    <groupId>com.squareup.okhttp3groupId>
    <artifactId>okhttpartifactId>
    <version>${okhttp.version}version>
dependency>


<dependency>
    <groupId>com.google.code.gsongroupId>
    <artifactId>gsonartifactId>
    <version>${gson.version}version>
dependency>
  • controller
@CrossOrigin
@Controller
@RequestMapping("/api/ucenter/wx")
@Slf4j
public class WxLoginController {

    @Autowired
    private LoginService loginService;

    /**
     * 回调地址
     */
    @GetMapping("/callback")
    public String callback(String code, String state, HttpServletRequest request, Model model) throws Exception {
        log.info("================== 微信回调执行,传入参数: code: {}, state: {}  ==========================", code, state);
        SongResult result = loginService.callback(code, state, request);
        if (!result.isSuccess()) {
            throw new Exception(result.getMessage());
        }
        return "redirect:http://localhost:3000?token=" + result.getData();
    }
}
  • 封装微信用户数据实体
package com.song.cms.entity;

import lombok.Data;

@Data
public class WechatTokenInfo {

    private String access_token;
    private String openid;

    // 唯一标识
    private String unionid;
    private String nickname;
    private String headimgurl;
    private Integer sex;

}
  • SongResult
package com.song.common;

import org.springframework.http.HttpStatus;

import java.util.HashMap;

public class SongResult extends HashMap<String, Object> {

    public void code(HttpStatus status) {
        this.put("code", status.value());
    }

    public SongResult message(String message) {
        this.put("message", message);
        return this;
    }

    public SongResult data(Object data) {
        this.put("data", data);
        return this;
    }

    public SongResult success() {
        this.code(HttpStatus.OK);
        this.message("操作成功!");
        return this;
    }

    public SongResult fail() {
        this.code(HttpStatus.INTERNAL_SERVER_ERROR);
        this.message("操作失败!");
        return this;
    }

    public SongResult notFound() {
        this.code(HttpStatus.NOT_FOUND);
        this.message("您访问的数据不存在!");
        return this;
    }

    @Override
    public SongResult put(String key, Object value) {
        super.put(key, value);
        return this;
    }

    /**
     * 校验是否OK
     */
    public boolean isSuccess() {
        return (int) this.get("code") == HttpStatus.OK.value();
    }

    /**
     * 获得消息
     */
    public String getMessage() {
        return (String) this.get("message");
    }

    /**
     * 获得数据
     */
    public Object getData() {
        return this.get("data");
    }
}

  • service
 /**
     * wx回调接口地址
     *
     * @param code    code
     * @param state   state
     * @param request request
     */
    @Override
    public SongResult callback(String code, String state, HttpServletRequest request) throws IOException {
        SongResult result = new SongResult();
		
        // 获得access_token
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        String accessTokenUrl = String.format(url, wechatProperties.getAppId(), wechatProperties.getAppSecret(), code);

        OkHttpClient client = new OkHttpClient();
        Request req = new Request.Builder().url(accessTokenUrl).build();
        Response response = client.newCall(req).execute();

        if (!response.isSuccessful()) {
            log.error(" ======== 获取微信access_token响应失败! ========");
            return result.fail().message("登录失败");
        }

        // 获得微信用户token
        String tokenInfo = Objects.requireNonNull(response.body()).string();
        Gson gson = new Gson();
        WechatTokenInfo wechatTokenInfo = gson.fromJson(tokenInfo, WechatTokenInfo.class);

        String token = wechatTokenInfo.getAccess_token();
        if (StringUtils.isBlank(token)) {
            log.error(" ======== 获取微信access_token失败! access_token: {} ========", token);
            return result.fail().message("授权认证失败");
        }

        // 获得微信用户信息
        WechatTokenInfo wxUserInfo = getWxUserInfo(token, wechatTokenInfo.getOpenid());
        if (wxUserInfo == null) {
            log.error(" ======== 获取微信用户基本信息失败! token:{}. openid: {} ========", token, wechatTokenInfo.getOpenid());
            return result.fail().message("授权认证失败");
        }

        User dbUser = userService.getUserByWxUnionid(wxUserInfo.getUnionid());

        // 用户为空, 指引用户绑定手机号
        if (dbUser == null) {
            log.info(" ======== 【用户扫码登录】微信号尚未绑定,执行微信注册逻辑! 微信号: {},  ======== ", wxUserInfo.getUnionid());
            dbUser = new User();
            dbUser.setAvatar(wxUserInfo.getHeadimgurl());
            dbUser.setNickName(wxUserInfo.getNickname());
            dbUser.setSex(wxUserInfo.getSex());
            dbUser.setWxUnionid(wxUserInfo.getUnionid());
            dbUser.setDescription("注册用户");
            userService.save(dbUser);
        }

        dbUser.setLastLoginTime(LocalDateTime.now());
        userService.updateById(dbUser);

        //使用jwt根据member对象生成token字符串
        String jwtToken = JwtUtils.getJwtToken(String.valueOf(dbUser.getId()), dbUser.getNickName());
        return result.success().data(jwtToken);
    }

  • 获取微信用户信息
/**
     * 获得微信用户信息
     *
     * @param token  微信 token
     * @param openid 微信 openid
     * @return WechatTokenInfo
     */
public WechatTokenInfo getWxUserInfo(String token, String openid) {
    WechatTokenInfo wechatTokenInfo = null;
    
    String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
    String userInfoUrl = String.format(baseUserInfoUrl, token, openid);

    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder().url(userInfoUrl).build();

    try {

        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            String userInfo = Objects.requireNonNull(response.body()).string();
            Gson gson = new Gson();
            wechatTokenInfo = gson.fromJson(userInfo, WechatTokenInfo.class);
        }
        log.error(" ======== 获取微信用户基本信息: {} ========", wechatTokenInfo);

    } catch (Exception e) {
        log.error("获得微信用户基本信息失败! {}", e.getMessage());
    }

    return wechatTokenInfo;
}

你可能感兴趣的:(java,SpringBoot)