应用小程序验证工具包

<!-- 微信小程序API,可以实现微信登录,微信支付等功能--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>3.5.0</version> </dependency>
新建配置类WxConfiguration
package com.itmuch.usercenter.configuration;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
@Configurable
public class WxConfiguration {
@Bean
public WxMaConfig wxMaConfig(){
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid("wx48ecafb715371267");
config.setSecret("1644c28011c189f6186a1bc4f9205b6b");
return config;
}
@Bean
public WxMaService wxMaService(WxMaConfig wxMaConfig){
WxMaServiceImpl service = new WxMaServiceImpl();
service.setWxMaConfig(wxMaConfig);
return service;
}
}在控制器中就可以使用了
package com.itmuch.usercenter.controller.user;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.alibaba.csp.ahas.shaded.com.alibaba.acm.shaded.com.google.common.collect.Maps;
import com.itmuch.usercenter.auth.CheckLogin;
import com.itmuch.usercenter.domain.dto.user.JwtTokenRespDto;
import com.itmuch.usercenter.domain.dto.user.LoginRespDto;
import com.itmuch.usercenter.domain.dto.user.UserLoginDto;
import com.itmuch.usercenter.domain.dto.user.UserRespDto;
import com.itmuch.usercenter.domain.entity.user.User;
import com.itmuch.usercenter.service.user.UserService;
import com.itmuch.usercenter.util.JwtOperator;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/users")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@Resource
private WxMaService wxMaService;
@Autowired
private JwtOperator jwtOperatorl;
@GetMapping("/{id}")
@CheckLogin
public User findById(@PathVariable Integer id) {
log.info("我被请求了");
return this.userService.findUserById(id);
}
/**
* 模拟生成token
* @return
*/
@GetMapping("/gen-token")
public String genToken(){
HashMap<String, Object> objectObjectHashMap = Maps.newHashMap();
objectObjectHashMap.put("id", "1");
objectObjectHashMap.put("wxNickname", "fox");
objectObjectHashMap.put("role", "user");
return this.jwtOperatorl.generateToken(objectObjectHashMap);
}
@PostMapping("/login")
public LoginRespDto login(@RequestBody UserLoginDto userLoginDto) throws WxErrorException {
//微信小程序登陆的结果
WxMaJscode2SessionResult result = this.wxMaService.getUserService().getSessionInfo(userLoginDto.getCode());
//微信的openId,用户在微信上的唯一标识
String openId = result.getOpenid();
//查看用户是否已经注册,如果没有注册就注册(插入user表)
//如果已经注册
User user = this.userService.login(userLoginDto, openId);
//就颁发token
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("id", user.getId());
userInfo.put("wxNickName", user.getWxNickname());
userInfo.put("role", user.getRoles());
String token = jwtOperatorl.generateToken(userInfo);
log.info(
"用户{}登录成功,生成token = {} ,有效期为{}",
userLoginDto.getWxNickname(),
token,
jwtOperatorl.getExpirationTime()
);
//构建响应
return LoginRespDto.builder()
.userRespDto(
UserRespDto.builder()
.id(user.getId())
.avatarUrl(user.getAvatarUrl())
.bonus(user.getBonus())
.wxNickname(user.getWxNickname())
.build()
)
.jwtTokenRespDto(
JwtTokenRespDto.builder()
.expirationTime(jwtOperatorl.getExpirationTime().getTime())
.token(token)
.build()
)
.build();
}
}在findById加上自定义注解@checklogin
@checklogin利用切面进行设置
先定义一个注解
package com.itmuch.usercenter.auth;
public @interface CheckLogin {
}@checklogin利用切面进行设置
package com.itmuch.usercenter.auth;
import com.itmuch.usercenter.util.JwtOperator;
import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class CheckLoginAspect {
@Resource
private JwtOperator jwtOperator;
@Around("@annotation(com.itmuch.usercenter.auth.CheckLogin)")//只要加了checklogin注解的都会走这个方法
public Object checkLogin(ProceedingJoinPoint point) {
try {
//从header中获取token
//利用静态方法获取request
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("X-Token");
//检查token是否合法,是否过期,如果不通过直接抛异常,否则放行
Boolean isVaild = jwtOperator.validateToken(token);
if (!isVaild){
throw new SecurityException("token不合法或过期");
}
//检查通过,将用户信息放进request的attribute中
Claims claims = jwtOperator.getClaimsFromToken(token);
request.setAttribute("id",claims.get("id"));
request.setAttribute("wxNickname",claims.get("wxNickname"));
request.setAttribute("role",claims.get("role"));
//放行
return point.proceed();
}catch (Throwable throwable){
throw new SecurityException("token不合法或过期");
}
}
}设置自定义异常
package com.itmuch.usercenter.security;
public class SecurityException extends RuntimeException{
}设置自定义异常捕捉器
package com.itmuch.usercenter.auth;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//统一异常捕捉器
@RestControllerAdvice
@Slf4j
public class GlobalExceptionErrorHandler {
@ExceptionHandler(SecurityException.class)
public ResponseEntity<ErrorBody> error(SecurityException e) {
log.warn("发生securityException异常",e);
ResponseEntity<ErrorBody> errorBodyResponseEntity = new ResponseEntity<>(
ErrorBody.builder()
.body("Token非法,用户不允许访问")
.status(HttpStatus.UNAUTHORIZED.value())
.build(),
HttpStatus.UNAUTHORIZED
);
return errorBodyResponseEntity;
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class ErrorBody {
private Integer status;
private String body;
}总结:在访问192.168.0.100:8003/users/1的时候需要携带X-Token,不然会报错
同样将文件复制到内容中心,在/share/{id}接口上打上
@CheckLogin
注解,等携带X-Token访问时会报错,是因为内容中心的token没有传递到用户中心,一下是服务之间传递token的方式:
feign传递token(@RequestHeader)
package com.itmuch.content.controller.content;
import com.itmuch.content.auth.CheckLogin;
import com.itmuch.content.domain.dto.content.ShareDTO;
import com.itmuch.content.service.content.ShareService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/share")
public class ShareController {
@Resource
private ShareService shareService;
@GetMapping("/{id}")
@CheckLogin
public ShareDTO findById(@PathVariable Integer id, @RequestHeader("X-Token") String token){
return this.shareService.findById(id,token);
}
}加上@RequestHeader注解,将请求头的X-Token注入到token,修改相对应的代码逻辑


package com.itmuch.content.feignClient;
import com.itmuch.content.domain.dto.user.UserDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
//@FeignClient(name = "user-center",configuration = UserCenterFeignConfiguration.class)
@FeignClient(name = "user-center")
// fallback = UserCenterFeignClientFallback.class,
// fallbackFactory = UserCenterFeignClientFallbackFactory.class)
//用了fallbackFactory就不要用fallback,fallbackFactory会比fallback更加强大,可以返回错误信息;
public interface UserCenterFeignClient {
/**
* 当调用findById时会构造http://user-center/users/{id}
*
* @param id
* @return
*/
@GetMapping("/users/{id}")
UserDTO findUserById(@PathVariable Integer id,@RequestHeader("X-Token") String token);
}优点:操作简单
缺点:现在修改一个API就要修改这么多文件,如果很多API这样实现起来就很不现实
feign的拦截器(RequestInterceptor)
package com.itmuch.content.feignClient.interceptor;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
public class TokenRelayRequestIntecepor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
//1、获取token
//利用静态方法获取request
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("X-Token");
//2、传递token
//把指定的值放进name里面
if (StringUtils.isNotEmpty(token)) {
requestTemplate.header("X-Token",token);
}
}
}使用拦截器不需要改变其他代码,
配置拦截器有两种方式,可以在@feignclient中使用configuration,或者直接在配置文件中进行全局配置

随时随地看视频