Java实现微信登录

Java实现微信登录

代码实现微信授权
简单来说,微信授权分为四步:
1.授权登录接口,生成一个二维码在页面中。
2.用户点击授权成功后自动获取code。
3.浏览器自动利用code访问回调接口。
4.在回调接口中利用code登录,appId.appSecret进行登录获取token。
5.利用4获取的token再次访问接口INFO_URL 获取用户微信信息
6.再根据用户微信消息,进行本地信息存储,生成token,并将权限角色等信息返回至前端
7.至此整个微信登录过程结束

一.首先获取微信登录跳转地址

/**
     * 登录地址
     */
    private final static String LOGIN_URL = "https://open.weixin.qq.com/connect/qrconnect?" +
            "appid={appId}&" +
            "redirect_uri={redirect}&" +
            "response_type=code&" +
            "scope=snsapi_login&" +
            "state={state}";

    /**
     * 获取微信登录跳转地址
     * @return
     */
    @RequestMapping(value = "/api/common/wx/get-url", method = { RequestMethod.POST})
    @ApiOperation(value = "构建PC端微信登录地址", notes = "获取地址后直接跳转到登录地址,用户进行扫码登录")
    public ApiRest<WxUrlRespDTO> getUrl(@RequestBody WxUrlReqDTO reqDTO) {

        // state为登录跳转标识,可以跳转到h5页面
        String url = LOGIN_URL
                .replace("{appId}", wechatConfig.getSiteAppId())
                // 统一跳转地址
                .replace("{redirect}", baseConfig.getLoginRedirect())
                .replace("{state}", reqDTO.getState());

        WxUrlRespDTO respDTO = new WxUrlRespDTO();
        respDTO.setUrl(url);
        return success(respDTO);
    }

二.扫码成功后会回调该redirect的url

即 “/api/common/wx/redirect” 该回调接口地址

/**
     * 网站的微信登录跳转
     * @param code
     * @return
     */
    @GetMapping("/api/common/wx/redirect")
    @ApiOperation(value = "微信PC端登录回调地址")
    public ApiRest<SysUserLoginDTO> webRedirect(HttpServletResponse response, @RequestParam("code") String code,
                                                @RequestParam("state") String state) throws IOException {
        // 获取会话
        SysUserLoginDTO respDTO = wxLoginService.webLogin(
                wechatConfig.getSiteAppId(),
                wechatConfig.getSiteAppSecret(),
                code);
        String redirect = "";
        // 跳转到H5版本
        if(PlatformType.H5.equals(state)){
            redirect = baseConfig.getLoginSyncH5();
        }
        // 跳转到PC版本
        if(PlatformType.PC.equals(state)){
            redirect = baseConfig.getLoginSyncPc();
        }
        // 替换地址
        redirect = redirect
                .replace("{token}", respDTO.getToken())
                .replace("{roleType}", String.valueOf(respDTO.getRoleType()));
        if(StringUtils.isBlank(redirect)){
            return super.failure("同步登录参数错误或跳转地址未配置!");
        }
        response.sendRedirect(redirect);
        return null;
    }

会将扫码授权登录成功时返回的code一并携带,请求该回调地址

在该回调接口中,
// 获取会话wxLoginService.webLogin(wechatConfig.getSiteAppId(),wechatConfig.getSiteAppSecret(), code);
通过该方法真正获取微信相关信息

三.通过该方法wxLoginService.webLogin真正获取本人微信等相关信息

@Override
    public SysUserLoginDTO webLogin(String appId, String secret, String code) {
        //登录成功获取本人微信的相关信息
        WxInfoRespDTO rest = LoginUtils.requestInfo(appId, secret, code);

        // 登录并返回
        return sysUserService.loginByThird(LoginType.WECHAT, rest.getUqId(), rest.getNickName(), rest.getHeadimgurl());
    }

3.1 首先通过该appId,sercet,code,获取微信登录的token信息

    /**
     * 获取AccessToken
     */
    private static final String ACCESS_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={appId}&secret={appSecret}&code={code}&grant_type=authorization_code";

/**
     * 获取accessToken
     * @param appId
     * @param appSecret
     * @param code
     * @return
     */
    public static WxTokenRespDTO requestAccess(String appId, String appSecret, String code){

        // 构建完整请求URL
        String url = ACCESS_URL.replace("{appId}", appId)
                .replace("{appSecret}", appSecret)
                .replace("{code}", code);

        // 获得返回JSON
        String json = HttpClientUtil.getJson(url, null, null);

        log.info(json);

        // 转换为登录结果
        WxTokenRespDTO rest = JSON.parseObject(json, WxTokenRespDTO.class);

        return rest;
    }

3.2 利用该token再次请求获取微信用户个人相关信息

/**
     * 获取用户信息接口
     */
    private static final String INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={token}&openid={openid}";
    /**
     * 获取用户头像昵称等内容
     * @param appId
     * @param appSecret
     * @return
     */
    public static WxInfoRespDTO requestInfo(String appId, String appSecret, String code){

        // 获取accessToken
        WxTokenRespDTO token = requestAccess(appId, appSecret, code);

        // 获取用户信息
        String url = INFO_URL
                .replace("{token}", token.getAccessToken())
                .replace("{openid}", token.getOpenid());
		//发送httpGet请求
        String json = HttpClientUtil.getJson(url, null, null);

		//解析json结果 转化为Java对象
        WxInfoRespDTO rest =  JSON.parseObject(json, WxInfoRespDTO.class);

        return rest;
    }

WxInfoRespDTO 从微信中获取的用户信息:

public class WxInfoRespDTO extends BaseDTO {

    @ApiModelProperty(value = "会话标识", required=true)
    private String openId;

    @ApiModelProperty(value = "昵称", required=true)
    private String nickName;

    @ApiModelProperty(value = "性别", required=true)
    private Integer sex;

    @ApiModelProperty(value = "省份", required=true)
    private String province;

    @ApiModelProperty(value = "市", required=true)
    private String city;

    @ApiModelProperty(value = "国家", required=true)
    private String country;

    @ApiModelProperty(value = "头像地址", required=true)
    private String headimgurl;

    @ApiModelProperty(value = "头像地址", required=true)
    private String unionid;

    @ApiModelProperty(value = "头像地址", required=true)
    private List<String> privilege;

拿到微信登录后的相关信息后,进行本项目的登录

四.本项目微信登录后业务代码

@Override
    public SysUserLoginDTO loginByThird(String loginType, String openId, String nickName, String avatar) {

        String userId = sysUserBindService.findBind(loginType, openId);

        // 不存在,创建新的用户
        if (StringUtils.isBlank(userId)) {
            // 随机产生数据
            SysUserLoginDTO dto = this.saveAndLogin(
                    RandomStringUtils.randomAlphabetic(16),
                    "A01",
                    nickName,
                    avatar,
                    RandomStringUtils.randomAlphanumeric(32));
            // 建立绑定关系
            sysUserBindService.save(false, dto.getId(), loginType, openId);
            return dto;
        }
        // 校验用户状态&密码
        SysUser user = this.getById(userId);
        return this.checkAndLogin(user, null);
    }
    
    /**
     * 用户登录校验
     *
     * @param user
     */
    private SysUserLoginDTO checkAndLogin(SysUser user, String password) {

        if (user == null) {
            throw new ServiceException(ApiError.ERROR_90010001);
        }
        // 被禁用
        if (UserState.DISABLED.equals(user.getState())) {
            throw new ServiceException(ApiError.ERROR_90010005);
        }
        // 待审核
        if (UserState.AUDIT.equals(user.getState())) {
            throw new ServiceException(ApiError.ERROR_90010006);
        }
        if (!StringUtils.isBlank(password)) {
            boolean pass = PassHandler.checkPass(password, user.getSalt(), user.getPassword());
            if (!pass) {
                throw new ServiceException(ApiError.ERROR_90010002);
            }
        }
        return this.setToken(user);
    }

生成用户的token存储并将用户角色权限等信息,返回至前端

/**
     * 保存会话信息
     *
     * @param user
     * @return
     */
    @Override
    public SysUserLoginDTO setToken(SysUser user) {
        // 获取一个用户登录的信息
        String key = Constant.USER_NAME_KEY + user.getUserName();
        String json = redisService.getString(key);
        if (!StringUtils.isBlank(json)) {
            // 删除旧的会话
            redisService.del(key);
        }
        SysUserLoginDTO respDTO = new SysUserLoginDTO();
        BeanMapper.copy(user, respDTO);
        // 正常状态才登录
        if(UserState.NORMAL.equals(user.getState())){
            // 根据用户生成Token
            String token = JwtUtils.sign(user.getUserName());
            respDTO.setToken(token);
            // 添加角色信息
            this.fillRoleData(respDTO);
            // 权限表,用于前端控制按钮
            List<String> permissions = sysUserRoleService.findUserPermission(user.getId());
            respDTO.setPermissions(permissions);
            // 保存如Redis
            redisService.set(key, JSON.toJSONString(respDTO));
        }
        return respDTO;
    }

到此整个微信登录过程结束

你可能感兴趣的:(微信,java,开发语言)