spring boot实现微信的网页授权

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对象

@Component
public 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")
@Slf4j
public 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
@Slf4j
public 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.
 */
@ControllerAdvice
public 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

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值