美文网首页
基于java的微信公众号授权登录

基于java的微信公众号授权登录

作者: 张于宴 | 来源:发表于2018-11-28 12:26 被阅读0次

    实现业务:微信授权登录,调用后台接口,获取用户信息,实现自己系统中的用户登录业务。

    Ⅰ.开发前准备一网页授权回调域名

    首先要在公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名,微信公众平台测试号支持本地ip,这里在微信测试号中测试,微信公众平台测试地址

    微信截图_20181128111028.png

    具体而言,微信浏览器中网页授权流程分为四步
    1.用户进入授权页面,同意授权,获取code
    2.通过code换取网页授权access_token(与基础支持中的access_token不同)
    3.如果需要,开发者可以刷新网页授权access_token,避免过期
    4.通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

    Ⅱ.具体开发流程
    这里采用拦截器形式对需要用户信息的业务进行拦截,实现自己系统中的用户登录业务

    package com.jianshu.web.interceptor;
    import com.jianshu.common.utils.Constants;
    import com.jianshu.common.utils.StringUtils;
    import com.jianshu.common.utils.SystemKeys;
    import com.jianshu.modules.frontBase.model.User;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.annotation.Resource;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.net.URLEncoder;
    
    public class OAuth2Interceptor extends HandlerInterceptorAdapter {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2Interceptor.class);
    
        // 微信授权地址
        private static String authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
        // 微信授权方式 :应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid)
        // snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,
        // 即使在未关注的情况下,只要用户授权,也能获取其信息
        private static String SCOPE = "snsapi_userinfo";
        // private static String SCOPE = "snsapi_base";
        //微信授权获取登录凭证code接口
        private static String REDIRECT_URI = Constants.CONTEXT_DOMAIN + "wow/auth?redirect=REDIRECT_URL";
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            Cookie[] cookies = request.getCookies();
            String openid = "";
            if (cookies != null) {
                //这里是根据cookie的key获取value
                openid = SystemKeys.getUserInfo(cookies);
            }
            if (StringUtils.isBlank(openid)) {
                LOGGER.debug("###### wechat auth login !");
                String queryString = request.getQueryString();
                String redirectUrl = "";
                if(StringUtils.isNotBlank(queryString)){
                    redirectUrl = request.getRequestURL() + "?" + request.getQueryString();
                }
                String url = authUrl.replace("APPID", Constants.APPID).replace("SCOPE", SCOPE).replace("REDIRECT_URI", URLEncoder.encode(REDIRECT_URI.replace("REDIRECT_URL", redirectUrl), "utf-8"));
                response.sendRedirect(url);
                return false;
            }
           
            return super.preHandle(request, response, handler);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
    }
    
    
    微信授权获取登录凭证code接口
      @RequestMapping("wow/main")
        public String main(HttpServletRequest request, HttpServletResponse response, Model model) {
            return "web/main/index";
        }
    @RequestMapping("wow/auth")
        public String auth(HttpServletRequest request, HttpServletResponse response) {
            String code = request.getParameter("code");
            String openid = "";
            String redirectUrl = request.getParameter("redirect");
            try {
                String res = WXUtils.getOpenId(Constants.APPID, Constants.APPSECRET, code);
                LOGGER.info("openId from wx res:" + res);
                JSONObject json = JSONObject.fromObject(res);
                openid = json.getString("openid");
                String token = json.getString("access_token");
                if (StringUtils.isNotEmpty(openid)) {
                    //用户登录
                    User user = apiUserService.login(openid, token);
                    if (user != null) {
                        //用户信息存储到cookie
                        Cookie userCookie = new Cookie(Constants.User.COOKIE_KEY, openid);
                        userCookie.setMaxAge(-1);   //设置为“0”或负值时,关闭浏览器才会清除cookie
                        userCookie.setPath("/");
                        response.addCookie(userCookie);
                    }
                }
            } catch (Exception e) {
                LOGGER.error("程序错误", e);
                return "web/common/error";
            }
            if (StringUtils.isBlank(redirectUrl)) {
                //redirect 地址为空的话默认跳转到主页
                redirectUrl = "/wow/main";
            }
            return "redirect:" + redirectUrl;
        }
    
    自己系统中的用户登录业务逻辑
    package com.jianshu.web.frontBase.service;
    
    import com.jianshu.common.service.BaseService;
    import com.jianshu.common.utils.*;
    import com.jianshu.modules.frontBase.dao.UserDao;
    import com.jianshu.modules.frontBase.model.User;
    import com.jianshu.modules.frontBase.model.vo.UserVo;
    import com.jianshu.web.common.SessionUser;
    import net.sf.json.JSONObject;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Date;
    
    /**
     * userService
     * 
     * @author ritian
     * @date 2018年4月14日
     */
    @Service
    public class ApiUserService extends BaseService {
        @Resource
        private UserDao userDao;
    
        //根据openid 登录
        public User login(String openid, String token) {
            User user = this.findByOpenid(openid);
           //user为空则保存至数据库中
            if (user == null) {
                //根据token及openid获取用户信息
                JSONObject json = WXUtils.getUserInfo(token, openid);
                if(json != null){
                  user = getUser(json);
                  user.setOpenid(openid);
                 this.save(user);
               }
            }
            cacheUser(user);
            return user;
    
        }
    
        public User get(int id){
            return userDao.get(id);
        }
    
        /**
         * 缓存用户信息,
         *
         * @param user 需要被缓存的用户
         * @return 服务器缓存的用户信息
         */
        private void cacheUser(User user) {
            CacheUtils.put(Constants.Cache.USER_CACHE, user.getOpenid(), user);
        }
    
        public User findByOpenid(String openid) {
            return userDao.findByOpenid(openid);
        }
    
        /**
         * 保存
         */
        public void save(User t) {
            userDao.save(t);
        }
        private User getUser(JSONObject json) {
            User user = new User();
            user.setHeadImgUrl(json.optString("headimgurl"));
            user.setNickname(json.getString("nickname"));
            user.setCreateTime(new Date());
            user.setProvince(json.optString("province"));
            user.setCity(json.optString("city"));
            user.setGender(json.optInt("sex"));
            return user;
        }
    }
    
    

    相关工具类,根据token及openid获取用户信息

    参考微信官方文档一第四步:拉取用户信息(需scope为 snsapi_userinfo)

    package com.ccamazing.common.utils;
    
    import java.util.*;
    import java.util.concurrent.ConcurrentHashMap;
    
    import com.github.pagehelper.util.StringUtil;
    import net.sf.json.JSONObject;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.cache.Cache;
    
    /**
     * 微信工具类(公众号开发)
     * 
     * @author ritian
     * @date 2018年4月14日
     */
    public class WXUtils {
    
        // 获取access_token的接口地址(GET) 限2000(次/天)
        private final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
        // 获取jsapi_ticket的接口地址(GET) 限2000(次/天)
        private final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
        // 获取openId的接口地址
        private final static String oauth_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        // 获取网页授权微信用户信息地址
        private final static String sns_userinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESSTOKEN&openid=OPENID&lang=zh_CN";
    
        // 获取微信卡券api_ticket 接口地址
        private final static String api_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESSTOKEN&type=wx_card";
    
        private static final Logger logger = LoggerFactory.getLogger(WXUtils.class);
        
    
    
    
        /**
         * 获取网页授权微信用户信息
         */
        public static JSONObject getUserInfo(String token, String openId) {
            try {
                // 通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。
                String url = sns_userinfo_url.replace("ACCESSTOKEN", token).replace(
                        "OPENID", openId);
                String res = HttpUtils.doGet(url);
                return JSONObject.fromObject(res);
            } catch (Exception e) {
                logger.error("用户授权获取用户信息失败!", e);
            }
            return null;
        }
    }
    

    spring-mvc拦截器配置文件

    <!-- 拦截器 -->
        <mvc:interceptors>
            <mvc:interceptor>
                 <!-- 可根据自己的实际需求,拦截需要拦截的路径 -->
                <mvc:mapping path="/wow/**" />
                <!-- 注意 这里的微信授权地址不拦截 -->
                <mvc:exclude-mapping path="/wow/auth" />
                <bean class="com.jianshu.web.interceptor.OAuth2Interceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    

    到这里基本上就完成了微信授权网页登录了。至于其他业务扩展,可根据具体需求自己实现~~

    相关文章

      网友评论

          本文标题:基于java的微信公众号授权登录

          本文链接:https://www.haomeiwen.com/subject/itkaqqtx.html