spring boot实现微信的网页授权

来源:互联网 发布:冒险岛游戏数据 编辑:程序博客网 时间:2024/06/05 00:23

spring boot实现微信的网页授权

使用spring boot实现简单微信授权登录
这是第一篇在csdn发表的博客

一,添加maven依赖

<dependency>            <groupId>com.github.binarywang</groupId>            <artifactId>weixin-java-mp</artifactId>            <version>2.8.0</version></dependency>

二,添加微信相关的配置信息

这里使用的是第三方sdk来MP_OAuth2网页授权功能,想了解可以看这个
微信的授权登录需要用到公众号的appid和secret,我用的是测试号,将这些配置信息写到application.yml中

wechat:  appid: wx6*************6b  secret: 0******************************6

创建一个bean来接收配置信息,set和get方法这里省略了

@Component@ConfigurationProperties(prefix = "wechat")public class WechatAccountConfig {    /**公众号appid*/    private String appid;    /**公众号secret*/    private String secret;

用户在微信客户端中访问第三方网页,公众号就可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑,使用该sdk获取用户信息的步骤是首先构造网页授权url,当用户同意授权后,会回调所设置的url并把authorization code传过来,然后用这个code获得access token,其中也包含用户的openid等信息,代码如下:
首先将appid和secret放进一个WxMpService,创建一个WxMpService对象

@Componentpublic class WechatMpConfig {    @Autowired    private WechatAccountConfig accountConfig;    @Bean    public WxMpService wxMpService(){        //创建WxMpService实例并设置appid和sectret        WxMpService wxMpService = new WxMpServiceImpl();        //这里的设置方式是跟着这个sdk的文档写的        wxMpService.setWxMpConfigStorage(wxConfigProvider());        return wxMpService;    }    @Bean    public WxMpConfigStorage wxConfigProvider(){        WxMpInMemoryConfigStorage wxConfigProvider = new WxMpInMemoryConfigStorage();        wxConfigProvider.setAppId(accountConfig.getAppid());        wxConfigProvider.setSecret(accountConfig.getSecret());        return wxConfigProvider;    }}

三,编写微信授权代码获取openid

import lombok.extern.slf4j.Slf4j;import me.chanjar.weixin.common.api.WxConsts;import me.chanjar.weixin.common.exception.WxErrorException;import me.chanjar.weixin.mp.api.WxMpService;import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import wang.linge.config.ProjectUrlConfig;import wang.linge.enums.ResultEnum;import wang.linge.exception.MyException;import java.net.URLEncoder;/** * Created by linge on 2017/10/5. */@Controller@RequestMapping("/wechat")@Slf4jpublic class WechatController {    @Autowired    private WxMpService wxMpService;    @Autowired    private WxMpService wxOpenService;    @Autowired    private ProjectUrlConfig projectUrlConfig;    /**     * 访问这个时便会发起微信的网页授权     * @param returnUrl 发起授权是可携带的一个参数,我这里用的是下面将要用到的login()的地址,将获取到的openid传递过去     * @return     */    @GetMapping("/authorize")    public String authorize(@RequestParam("returnUrl") String returnUrl) {    //设置回调地址        String url = "http://localhost/wechat/userInfo";        String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAUTH2_SCOPE_BASE, URLEncoder.encode(returnUrl));        return "redirect:" + redirectUrl;    }    //微信回调时访问的地址  这里获得code和之前所设置的returnUrl    @GetMapping("/userInfo")    public String userInfo(@RequestParam("code") String code,                           @RequestParam("state") String returnUrl) {        WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();        try {            wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);        } catch (WxErrorException e) {            log.error("【微信网页授权】{}", e);        //抛出异常 自定义的  方便处理  可自己定义            throw new MyException(ResultEnum.WECHAT_MP_ERROR, e.getError().getErrorMsg());        }        String openId = wxMpOAuth2AccessToken.getOpenId();        return "redirect:" + returnUrl + "?openid=" + openId;    }}

四,编写login方法将当前登录用户的信息存入当前会话中

@GetMapping("login")public ModelAndView login(@RequestParam("openid") String openid,                              HttpServletResponse response,                              Map<String,Object> map){        //1,openid 去和数据库里面的数据匹配验证 这里只是演示就删掉没有了        //2,设置token至cookie  并设置过期时间        CookieUtil.set(response,CookieConstant.TOKEN,token,CookieConstant.EXPIRE);        return new  ModelAndView("redirect:http://localhost/index"));    }
import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.HashMap;import java.util.Map;/** * Cookie工具类 * Created by linge on 2017/10/17. */public class CookieUtil {    public static void set(HttpServletResponse response,                           String name,String value,                           int maxAge){        Cookie cookie = new Cookie(name, value);        cookie.setPath("/");        cookie.setMaxAge(maxAge);        response.addCookie(cookie);    }    /**     * 获取Cookie     * @param request     * @param name     * @return     */    public static Cookie get(HttpServletRequest request,                           String name){        Map<String, Cookie> map = readCookieMap(request);        if(map.containsKey(name)){            return map.get(name);        }else{            return null;        }    }    /**     * 将cookie封装成map     * @param request     * @return     */    public static Map<String,Cookie> readCookieMap(HttpServletRequest request){        Cookie[] cookies = request.getCookies();        Map<String,Cookie> map = new HashMap<>();        if(cookies != null){            for(Cookie cookie : cookies){                map.put(cookie.getName(),cookie);            }        }        return map;    }}
/** * Cookie常量 * Created by linge on 2017/10/17. */public interface CookieConstant {    String TOKEN = "token";    Integer EXPIRE = 7200 ;}

五,使用切面拦截所有请求验证是否已验证登录

import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.context.request.RequestAttributes;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import wang.linge.constant.CookieConstant;import wang.linge.constant.RedisConstant;import wang.linge.exception.AuthorizeException;import wang.linge.utils.CookieUtil;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;/** * Created by linge on 2017/10/17. */@Aspect@Component@Slf4jpublic class AuthorizeAspect {    @Autowired    private StringRedisTemplate redisTemplate;    @Pointcut("execution(public * wang.linge.controller.*.*(..))"+            "&& !execution(public * wang.linge.controller.UserController.*(..))")    public void verify(){    }    @Before("verify()")    public void doVerify(){        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();        HttpServletRequest request = requestAttributes.getRequest();        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);        if(cookie == null){            log.warn("【登录校验】,无法在cookie中查找到token的值");            throw new AuthorizeException();        }        String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue()));        if(StringUtils.isEmpty(tokenValue)){            log.warn("【登录校验】,无法在redis中查找到token的值");            throw new AuthorizeException();        }    }}

六,处理未登录的异常,引导到登陆链接

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.ResponseStatus;import org.springframework.web.servlet.ModelAndView;import wang.linge.config.ProjectUrlConfig;import wang.linge.exception.Exception;import wang.linge.exception.AuthorizeException;/** * Created by linge on 2017/10/18. */@ControllerAdvicepublic class ExceptionHandler {    //为了方便将一些url写到配置里去  这里就不贴出来 可不用这个直接写地址或者仿照之前微信appid的配置写这个配置    @Autowired    private ProjectUrlConfig urlConfig;    @ExceptionHandler(AuthorizeException.class)    public ModelAndView handlerAuthorizeException(){        return new ModelAndView("redirect:"                .concat(urlConfig.getWechatOpenAuthorize())                .concat("/wechat/qrAuthorize")                .concat("?returnUrl=")                .concat("http://localhost/login"));    }}

参考资料:

微信官方文档

所用到的第三方SDK

原创粉丝点击