企业微信登陆

栏目: ASP.NET · 发布时间: 4年前

内容简介:用户登陆时,原设计是使用工号加密码进行登陆,只是工号不好记,为了推广,设计了企业微信登陆。企业微信中可以设置自建应用,其实就是内嵌了一个

引言

用户登陆时,原设计是使用工号加密码进行登陆,只是工号不好记,为了推广,设计了企业微信登陆。

企业微信登陆

企业微信中可以设置自建应用,其实就是内嵌了一个 Chrome ,点击左侧的自建应用,会在右侧浏览器显示相关应用,所有工作都放在企业微信中,需实现当前企业微信账号自动登陆系统。

企业微信登陆

开发的过程很坎坷。让微信折腾的一点脾气都没有。

当时不会调试,因为企业微信中的自建应用要求设置成线上地址,写好了,打包,传给服务器,然后再测试。

五点,觉得还有十分钟就写完了,写完了就去吃饭。

六点、八点,改到九点半,都要改哭了,还是不好使,最后放弃了。

后来邢彦年师兄帮我梳理流程,潘老师教我调试方法,才完成这个功能。

感谢邢彦年师兄和潘老师。

实现

文档

找文档一定要找对地方,两个 API ,一个服务端,一个客户端。

企业微信登陆

最开始我以为是使用客户端的 API 呢?点进去学了学,企业微信小程序可用的 API 接口,这个用不了,此应用不是小程序。然后 JS-SDK 不支持登陆授权。

企业微信登陆

相关文档在服务端 API 中的身份认证一节中。

OAuth 2.0

当我们用微信登陆某个网站时,会出现类似这样的授权页面。

企业微信登陆

点击确认登陆,该应用就能获取到用户相关的信息。

用户通过用户名和密码的方式进行微信的使用,第三方应用想获取微信用户信息,不是通过用户名密码,而是微信提供的令牌,这就是 OAuth 2.0 ,既可以让应用获取不敏感的信息,又可以保证账户的安全性。

更多内容可学习阮一峰的博客,写得非常好: OAuth 2.0 的一个简单解释 - 阮一峰的网络日志

登陆流程

用户点开应用,实际上是访问当前系统微信授权的入口

企业微信登陆

微信网页授权地址: https://open.weixin.qq.com/connect/oauth2/authorize

参数 说明
appid 企业的 CorpID
redirect_uri 授权后的回调地址, 需使用 urlencode 处理
response_type 回调数据返回类型
scope 应用授权作用域。企业自建应用固定填写: snsapi_base
state 回调时额外的参数,非必选
#wechat_redirect 终端使用此参数判断是否需要带上身份信息

看这个表格也是在无聊,下面是我配置好的微信授权链接,大家只需将相应参数改写即可。 注:回调的 url 一定要使用 encodeURIComponent 处理!

https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxx&redirect_uri=https%3A%2F%2Falice.dgitc.net%2Fsetup%2Fwechat&response_type=code&scope=snsapi_base#wechat_redirect

用户静默授权成功,跳转到回调地址

用户授权成功后,会带着 code 参数重定向到回调地址。

类似这样:

https://alice.dgitc.net/setup/wechat?code=xxxxxx

前台的组件就通过路由获取到了 code ,然后通过 code 去进一步获取用户信息。

const code = this.route.snapshot.queryParamMap.get('code');
this.userService.enterpriseWeChatLogin(code).subscribe(...);

后台通过 code 找微信后台获取用户信息

这个是分成两次获取,先获取 access_token ,再通过 access_tokencode 获取用户信息。

GET请求 https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET

这个是获取 access_token 的地址,获取 access_token 的过程是重点!

上面传的参数名是 corpidcorpsecret ,企业 id 和密钥。

企业微信登陆

企业微信登陆

这是企业微信的设计,企业 id 是一个,标识这个企业,每一个功能模块都有相应的 secret

然后企业 idsecret 配对,获取到只能访问这个功能模块的一个 access_token

企业微信登陆

企业微信登陆

就拿当前 Alice 系统来举例,自建应用 Alice 存在 secret ,通过此 secretcorpid 获取到 access_token ,即相当于拿到了受保护 API 的访问权限。

因为这个 access_token 是通过 Alice 应用的 secret 获取到的,所以再用它访问其他的功能,是不合法的。

access_token 有访问频率限制,所以设计了一套缓存方案。

@Override
public String getAccessTokenBySecret(String secret) {
    logger.debug("从缓存中获取令牌");
    String access_token = this.cacheService.get(secret);

    logger.debug("如果获取到了,直接返回");
    if (null != access_token) {
        return access_token;
    }

    logger.debug("否则,发起HTTP请求");

    logger.debug("获取企业验证信息");
    String url = enterpriseInformation.getAccessTokenUrl();
    String corpId = enterpriseInformation.getCorpid();

    logger.debug("获取认证令牌");
    ResponseEntity<EnterpriseAuth> responseEntity = restTemplate.getForEntity(url + "?corpid=" + corpId + "&corpsecret=" + secret, EnterpriseAuth.class);

    logger.debug("如果请求成功");
    if (responseEntity.getStatusCode().is2xxSuccessful()) {
        logger.debug("获取响应体");
        EnterpriseAuth enterpriseAuth = responseEntity.getBody();
        Assert.notNull(enterpriseAuth, "微信令牌为空");

        logger.debug("如果微信请求成功");
        if (enterpriseAuth.successed()) {
            logger.debug("存储缓存,返回令牌");
            access_token = enterpriseAuth.getAccessToken();
            this.cacheService.put(secret, access_token, enterpriseAuth.getExpiresIn(), TimeUnit.SECONDS);
            return access_token;
        }
    }

    logger.debug("请求失败,返回空令牌");
    return "";
}

缓存是通过把 Redis 工具类包装了一下实现的,很简单。

@Service
public class CacheServiceImpl implements CacheService {

    /**
     * Redis操作模版
     */
    private final StringRedisTemplate redisTemplate;
    private final ValueOperations<String, String> valueOperations;

    @Autowired
    public CacheServiceImpl(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
        this.valueOperations = redisTemplate.opsForValue();
    }

    @Override
    public void put(String key, String value, Long time, TimeUnit timeUnit) {
        this.valueOperations.set(key, value, time, timeUnit);
    }

    @Override
    public String get(String key) {
        return this.valueOperations.get(key);
    }

    @Override
    public void clear(String key) {
        this.redisTemplate.delete(key);
    }
}

access_tokencode 都有了,终于可以获得用户信息了。

GET请求 https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE

这个简单了,问题出在数据不规范的问题上,大写的 json ,如果按这样建,实体就不符合 java 规范了。

{
   "errcode": 0,
   "errmsg": "ok",
   "UserId":"USERID",
   "DeviceId":"DEVICEID"
}

最后在字段添加 JsonAlias 注解。

@JsonAlias("UserId")
private String userId;

这里获取到的信息是用户的 userId ,这个 userId 和我们熟知的 openId 是不一样的。

userId 就是管理员为用户在企业内设置的唯一标识,企业内唯一。

具体的后台获取 userId 的细节:

@Override
public Boolean enterpriseWeChatLogin(String code) {
    logger.debug("构造参数");
    String secret = this.enterpriseInformation.getAgentSecret();
    String access_token = this.aliceCommonService.getAccessTokenBySecret(secret);
    String url = this.enterpriseInformation.getUserInfoUrl() + "?code=" + code + "&access_token=" + access_token;

    logger.debug("请求用户信息");
    ResponseEntity<EnterpriseUser> responseEntity = this.restTemplate.getForEntity(url, EnterpriseUser.class);

    logger.debug("如果请求成功");
    if (responseEntity.getStatusCode().is2xxSuccessful()) {
        logger.debug("获取响应体");
        EnterpriseUser enterpriseUser = responseEntity.getBody();
        Assert.notNull(enterpriseUser, "企业用户不能为空");

        logger.debug("如果企业微信端也成功了");
        if (enterpriseUser.successed()) {
            logger.debug("获取userId");
            String wxId = enterpriseUser.getUserId();

            logger.debug("如果有userId,说明当前用户存在此企业中");
            if (null != wxId) {
                // 请自行填充登陆的具体细节
            }
        } else if (enterpriseUser.tokenInvalided()) {
            logger.debug("token不合法,清空缓存,重新获取");
            this.cacheService.clear(secret);

            return this.enterpriseWeChatLogin(code);
        }
    }

    logger.debug("其他一律返回false");
    return false;
}

前台跳转,登陆成功

前台在订阅中添加跳转方法,登陆成功后,跳转到首页,登陆失败, 401 走拦截器,跳转到登陆页。

this.userService.enterpriseWeChatLogin(code)
    .subscribe(() => {
        this.userService.setCurrentLoginUser();
        this.router.navigateByUrl('main');
    }, () => {
        console.log('network error');
    });

Host

一定要记住,非常重要!!!

企业微信登陆

以后再碰到只能访问线上地址的情况,想在本地调试,一定要改 Host !!!

总结

最后的总结就是多想想潘老师评论的这句话,有些路总不过去,很大的可能是方法错了。

企业微信登陆


以上所述就是小编给大家介绍的《企业微信登陆》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

More Effective C++(中文版)

More Effective C++(中文版)

梅耶(Scott Meyers) / 侯捷 / 电子工业出版社 / 2011-1-1 / 59.00元

《More Effective C++:35个改善编程与设计的有效方法(中文版)》是梅耶尔大师Effective三部曲之一。继Effective C++之后,Scott Meyers于1996推出这本《More Effective C++(35个改善编程与设计的有效方法)》“续集”。条款变得比较少,页数倒是多了一些,原因是这次选材比“一集”更高阶,尤其是第5章。Meyers将此章命名为技术(tec......一起来看看 《More Effective C++(中文版)》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具