微信点餐之后台扫码登录(11)

微信开放平台:https://open.weixin.qq.com/ 扫描登录不支持个人账号
最终的微信登录事件的地址为:
http://applenst.natapp4.cc/sell/wechat/qrAuthorize?returnUrl=applenst.natapp4.cc/sell/seller/login
不走登录授权的测试地址为
http://applenst.natapp4.cc/sell/seller/login?openid=123qwe

新增卖家账号

创建javabean

package com.imooc.vo.admin;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
 * @author: menghaibin
 * @create: 2020-02-26 15:24
 * @description: 卖家信息
 **/
Data
Entity
public class SellerInfo {

    @Id
    @Column(name = "seller_id")
    private String sellerId;

    @Column(name = "username")
    private String username;

    @Column(name = "password")
    private String password;

    @Column(name = "openid")
    private String openid;

}

创建dao层接口

com\imooc\dao\SellerInfoDao.java

package com.imooc.dao;

import com.imooc.vo.admin.SellerInfo;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by Administrator on 2020/2/26.
 */
public interface SellerInfoDao extends JpaRepository<SellerInfo,String>{

    public SellerInfo findByOpenid(String openid);

    public SellerInfo save(SellerInfo sellerInfo);
}

创建测试类

package com.imooc.dao;

import com.imooc.utils.JsonUtil;
import com.imooc.vo.admin.SellerInfo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * Created by Administrator on 2020/2/26.
 */
RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
public class SellerInfoDaoTest {

    @Autowired
    SellerInfoDao sellerInfoDao;
    @Test
    public void findByOpenid() throws Exception {

        SellerInfo sellerInfo = sellerInfoDao.findByOpenid("123qwe");
        log.info(JsonUtil.toJson(sellerInfo));
    }

    @Test
    public void save() throws Exception {

        SellerInfo sellerInfo = new SellerInfo();
        sellerInfo.setSellerId("123456");
        sellerInfo.setUsername("admin");
        sellerInfo.setPassword("admin");
        sellerInfo.setOpenid("123qwe");
        sellerInfoDao.save(sellerInfo);
    }

}

卖家扫码(获取到openid)

创建service层接口

com\imooc\service\SellerService.java

package com.imooc.service;

import com.imooc.vo.admin.SellerInfo;

public interface SellerService {

    /*通过openid查询卖家端信息*/
    public SellerInfo findSellerInfoByOpenid(String openid);
}

创建service层接口的实现类

com\imooc\service\imp\SellerServiceImp.java

package com.imooc.service.imp;

import com.imooc.dao.SellerInfoDao;
import com.imooc.service.SellerService;
import com.imooc.vo.admin.SellerInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author: menghaibin
 * @create: 2020-02-26 15:39
 * @description: 卖家端登录
 **/
@Service
public class SellerServiceImp implements SellerService{
    @Autowired
    private SellerInfoDao sellerInfoDao;
    @Override
    public SellerInfo findSellerInfoByOpenid(String openid) {
        return sellerInfoDao.findByOpenid(openid);
    }
}

在application.yml文件中追加appid以及Secret

 #开发平台接入的公众号appid
 openAppId: wxf1687xxxxxxxxxxb
 #开发平台接入的公众号Secret
 openAppSecret: b65d46d51xxxxxxxxxxxxxxxx6ff886d71

在WechatAccountConfig.java文件中追加appid以及Secret属性

/*开放平台微信登录appid*/
private String openAppId;

/*开放平台微信登录app Secret*/
private String openAppSecret;

创建微信登录配置类

com\imooc\config\WeChatOpenConfig.java

package com.imooc.config;

import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @author: menghaibin
 * @create: 2020-02-26 20:14
 * @description: 微信登录配置
 **/
@Component
public class WeChatOpenConfig {

    @Autowired
    private WechatAccountConfig accountConfig;

    @Bean
    public WxMpService wxOpenService(){
        WxMpService wxOpenService = new WxMpServiceImpl();
        wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage());
        return wxOpenService;
    }

    @Bean
    public WxMpConfigStorage wxOpenConfigStorage(){
        WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage();
        wxMpInMemoryConfigStorage.setAppId(accountConfig.getOpenAppId());
        wxMpInMemoryConfigStorage.setSecret(accountConfig.getOpenAppSecret());
        return wxMpInMemoryConfigStorage;
    }
}

controller实现

在WechatController.java类中追加微信登录qrAuthorize和qrUserInfo的实现,获取openid

/*微信登录*/
@GetMapping("qrAuthorize")
 public String qrAuthorize(@RequestParam("returnUrl") String returnUrl){
      /*url:授权成功后要跳转的路径*/
     String url = accountConfig.getDomainUrl() + "/sell/wechat/qrUserInfo";
     String redirectUrl = wxMpService.buildQrConnectUrl(url,WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN,URLEncoder.encode(returnUrl));
     log.info(redirectUrl);
      /*进行跳转*/
     return "redirect:"+redirectUrl;
 }

/*微信登录回调方法*/
@GetMapping("/qrUserInfo")
public String qrUserInfo(@RequestParam("code") String code,
                         @RequestParam("state") String returnUrl){

    /*code:授权成功后会返回一个code
    * state:授权成功后的原始参数*/
    WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
    try{
        wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
    }catch (WxErrorException e){
        log.error("微信授权失败");
    }
    /*得到openid*/
    String openId = wxMpOAuth2AccessToken.getOpenId();

    /*跳转到系统*/
    return "redirect:"+ returnUrl + "?openid="+openId;
}

卖家登录(获取到openid之后)

通过微信登录获取到用户的openid,通过查询数据库是否存在,如果不存在 则跳到错误页,如果存在,则设置一个token到redis 同时把token设置到cookie
1:在application.yml中配置reids链接信息

  redis:
    host: 192.168.1.106
    port: 6379

1:创建微信登录controller
com\imooc\controller\SellerUserController.java

package com.imooc.controller;

import com.imooc.config.WechatAccountConfig;
import com.imooc.exception.SellException;
import com.imooc.service.SellerService;
import com.imooc.utils.CookieUtil;
import com.imooc.vo.admin.SellerInfo;
import com.imooc.vo.enums.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
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 org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author: menghaibin
 * @create: 2020-02-26 20:55
 * @description: 卖家后台登录 登出
 **/
@Controller
@RequestMapping("/seller")
@Slf4j
public class SellerUserController {

    @Autowired
    private SellerService sellerService;
    /*注解:redis 工具类*/
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private WechatAccountConfig accountConfig;
}

2:在刚才创建的SellerUserController中实现login方法

@GetMapping("/login")
public ModelAndView login(@RequestParam("openid") String openid,
                  HttpServletResponse response,
                  Map<String,Object> map){
    //1:数据库查询openid是否存在
    SellerInfo sellerInfo = sellerService.findSellerInfoByOpenid(openid);
    if(sellerInfo == null){
        throw new SellException(ResultEnum.LOGIN_FAIL);
    }
    //2:设置token至redis
    String token = UUID.randomUUID().toString();
    Integer expire = 7200;//过期时间 2小时
    /*参数1:key 格式化 以token_开头
    * 参数2:value
    * 参数3:过期时间
    * 参数4:过期时间的单位
    * */
    //把openid作为value存入reids
    redisTemplate.opsForValue().set(String.format("token_%s",token),openid,expire,TimeUnit.SECONDS);
    log.info(String.format("token_%s",token));
    //3:设置token至cookie 访问成功后 通过检查可以看到前端有了cookie
    CookieUtil.setCookie(response,"token",token,expire);
    log.info("成功");
    //跳转绝对地址
    /*思路:
    * 先设置token到redis key=(格式化)token_we23332234434 value=opeind_12345664
    * 在设置token到cookie 格式为token:we23332234434
    * 验证的时候通过拿到cookie的token值we23332234434去redis获取key([格式化]token_we23332234434)的值opeind_12345664存在不存在
    * */
    return new ModelAndView("redirect:"+accountConfig.getDomainUrl()+"/sell/seller/order/list");

}

卖家注销

在SellerUserController中实现logout方法

@GetMapping("/logout")
public ModelAndView logout(HttpServletRequest request,HttpServletResponse response,
                    Map<String,Object> map){
    //从cookie查询
    Cookie cookie = CookieUtil.getCookie(request,"token");
    if(cookie != null){
        //清除reids
        redisTemplate.opsForValue().getOperations().delete(String.format("token_%s",cookie.getValue()));
        //清除cookie
        CookieUtil.setCookie(response,"token",null,0);
    }

    map.put("msg",ResultEnum.LOGOUT_SUCCESS.getMsg());
     /*按实际业务跳转*/
    map.put("url","/sell/seller/order/list");
    return new ModelAndView("common/success",map);
}

请求拦截验证

面向切面技术:取到cookie 在根据cookie得到reids的value 如果存在则不拦截
1:定义一个exception类
com\imooc\exception\SellerAuthorizeException.java

package com.imooc.exception;

/**
 * @author: menghaibin
 * @create: 2020-02-27 11:34
 * @description: 登录校验的异常类 使用者为SellerAuthorizeAspect
 **/
public class SellerAuthorizeException extends RuntimeException{
}

2:定义一个切面
com\imooc\aspect\SellerAuthorizeAspect.java

package com.imooc.aspect;

import com.imooc.exception.SellerAuthorizeException;
import com.imooc.utils.CookieUtil;
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.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

/**
 * @author: menghaibin
 * @create: 2020-02-27 11:21
 * @description: 切面 用于token验证
 **/
@Component
@Aspect
@Slf4j
public class SellerAuthorizeAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /*定义切入点
    * 拦截contorller下的seller开头的类的所有方法 但排除SellerUserController
    * */
    @Pointcut("execution(public * com.imooc.controller.Seller*.*(..))" +
    "&& !execution(public * com.imooc.controller.SellerUserController.*(..))")
    public void verify(){};

    @Before("verify()")
    public void doVerify(){
        /*获取HttpServletRequest*/
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        /*查询cookie*/
        Cookie cookie = CookieUtil.getCookie(request,"token");
        if(cookie == null){
            log.warn("[登录校验] cookie中查询不到token");
            throw new SellerAuthorizeException();
        }

        /*查询redis*/
        String redisValue = redisTemplate.opsForValue().get(String.format("token_%s",cookie.getValue()));
        log.info(redisValue);
        if(StringUtils.isEmpty(redisValue)){
            log.warn("[登录校验] redis中查询不到token");
            throw new SellerAuthorizeException();
        }

    }
}

3:定义一个捕获异常的handler
com\imooc\handler\SellerExceptionHandler.java

package com.imooc.handler;

import com.imooc.config.WechatAccountConfig;
import com.imooc.exception.SellException;
import com.imooc.exception.SellerAuthorizeException;
import com.imooc.vo.front.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
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.servlet.ModelAndView;

/**
 * @author: menghaibin
 * @create: 2020-02-27 11:51
 * @description: 登录校验异常捕获
 **/
@ControllerAdvice
public class SellerExceptionHandler {
    @Autowired
    private WechatAccountConfig accountConfig;

    //拦截登录异常
    @ExceptionHandler(value = SellerAuthorizeException.class)
    public ModelAndView handlerAuthorizeException(){
        /*跳转到微信登录地址 http://applenst.natapp4.cc/sell/wechat/qrAuthorize?returnUrl=applenst.natapp4.cc/sell/seller/login*/
        return  new ModelAndView("redirect:"
        .concat(accountConfig.getDomainUrl())
        .concat("/sell/wechat/qrAuthorize")
        .concat("?returnUrl=")
        .concat(accountConfig.getDomainUrl())
        .concat("/sell/seller/login"));

    }

    /*拦截常规异常*/
    @ExceptionHandler(value = SellException.class)
    @ResponseBody
    public ResultVo handlerSellerException(SellException e){
        ResultVo resultVo = new ResultVo();
        resultVo.setCode(e.getCode());
        resultVo.setMsg(e.getMessage());
        return resultVo;
    }
}

posted @ 2020-04-01 15:34  努力的校长  阅读(440)  评论(0编辑  收藏  举报