当前位置: 首页 > news >正文

微信小程序授权登录+JWT

**备注:**依赖有点老了,新版0.11.5,若用新版工具类自行封装,为了后台不改动,我只能凑合用了

		<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>

工具类:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** JWT 工具类(兼容 jjwt 0.9.1)* 用于生成和解析 JWT Token*/
@Component
public class JwtUtil {// 令牌秘钥@Value("${token.secret}")private String SECRET_KEY;private static final long EXPIRATION_TIME = 1000L * 60 * 60 * 24 * 7; // 7 天,单位毫秒/*** 生成 JWT Token* @param openId 用户唯一标识,如微信 openid* @return JWT Token 字符串*/public String generateToken(String openId) {Map<String, Object> claims = new HashMap<>();claims.put("openId", openId); // 可放入自定义信息,比如用户ID等return Jwts.builder().setClaims(claims) // 自定义 claims.setSubject(openId)  // 主题,通常也放 openid.setIssuedAt(new Date()) // 签发时间.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 过期时间.signWith(SignatureAlgorithm.HS256, SECRET_KEY) // ✅ 使用字符串密钥.compact();}/*** 从 Token 中解析出 openid* @param token JWT Token* @return openid*/public String getOpenIdFromToken(String token) {Claims claims = Jwts.parser().setSigningKey(SECRET_KEY) // ✅ 使用字符串密钥.parseClaimsJws(token).getBody();return claims.getSubject();}
}

拦截器:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bladex.common.utils.JwtUtil;
import com.bladex.sp.domain.WxUser;
import com.bladex.sp.mapper.WxUserMapper;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Slf4j
@Component
@RequiredArgsConstructor
public class JwtInterceptor implements HandlerInterceptor {@Resourceprivate WxUserMapper userMapper;@Resourceprivate JwtUtil jwtUtil;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取请求头中的 AuthorizationString authHeader = request.getHeader("Authorization");if (StrUtil.isBlank(authHeader) || !authHeader.startsWith("Bearer ")) {log.warn("无效的 Token");responseError(response, "Token无效");return false;}//提取 tokenString token = authHeader.substring(7);try {//解析 token 得到 openidString openid = jwtUtil.getOpenIdFromToken(token);//根据 openid 查询用户WxUser wxUser = userMapper.selectWxUserByOpenId(openid);if (wxUser == null) {log.warn("用户不存在,openid: {}", openid);responseError(response, "用户不存在");return false;}//将用户信息存入请求属性中(供 Controller 使用)request.setAttribute("wxUser", wxUser);//✅ 至此,用户已鉴权,放行请求return true;} catch (Exception e) {log.error("Token 解析失败: {}", e.getMessage());responseError(response, "Token无效: " + e.getMessage());return false;}}private void responseError(HttpServletResponse response, String message) throws Exception {JSONObject data = new JSONObject() {{put("code", HttpServletResponse.SC_UNAUTHORIZED);put("message", message);}};response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write(JSON.toJSONString(data));response.setCharacterEncoding("utf-8");response.setContentType("application/json");}
}

拦截器注册到 Spring MVC 拦截链,配置类:

import com.bladex.framework.interceptor.JwtInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {private final JwtInterceptor jwtInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor).addPathPatterns("/api/**") // 只拦截小程序相关接口.addPathPatterns("/auth/**") // 只拦截小程序相关接口// 如果登录接口不需要拦截,可以排除.excludePathPatterns("/auth/wxLogin");}
}

实体类:

@Data
public class WxUserDTO implements Serializable {private String code;//昵称private String nickName;//头像private String avatarUrl;//性别:0.男 1.女private Integer gender;
}@EqualsAndHashCode(callSuper = true)
@Data
@Builder
public class WxUser extends BaseEntity {//主键idprivate Long id;//openId唯一private String openId;//昵称private String nickName;//头像private String avatar;//性别:0.男 1.女private Integer gender;
}@Data
@Builder
public class WxLoginVO implements Serializable {private String token;private WxUser user;
}

controller:

	//微信授权登录@PostMapping("/wxAuthLogin")public AjaxResult wxAuthLogin(@RequestBody WxUserDTO dto) {return AjaxResult.success(authService.wxAuthLogin(dto));}

service:

	@Resourceprivate JwtUtil jwtUtil;@Resourceprivate WechatConfig wechatConfig;@Resourceprivate RestTemplate restTemplate;@Resourceprivate WxUserMapper userMapper;//微信授权登录public WxLoginVO wxAuthLogin(WxUserDTO dto) {Assert.isFalse(StringUtils.isBlank(dto.getCode()), "微信授权code不能为空");String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",wechatConfig.getAppId(), wechatConfig.getAppSecret(), dto.getCode());ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);JSONObject body = JSON.parseObject(response.getBody());log.info("微信授权登录返回结果: {}", body);if (body.containsKey("errcode")) {Integer errcode = body.getInteger("errcode");String errmsg = body.getString("errmsg");log.error("微信接口调用失败, errcode: {}, errmsg: {}", errcode, errmsg);throw new RuntimeException("微信授权失败:" + errmsg);}Assert.isTrue(body.containsKey("openid"), "授权失败,错误信息: " + body.getString("errmsg"));String openId = body.getString("openid");WxUser wxUser = userMapper.selectWxUserByOpenId(openId);if (StringUtils.isNull(wxUser)) {WxUser buildUser = WxUser.builder().openId(openId).nickName(dto.getNickName()).avatar(dto.getAvatarUrl()).gender(dto.getGender()).build();buildUser.setCreateTime(DateUtils.getNowDate());int i = userMapper.insertWxUser(buildUser);if (i > 0) {wxUser = buildUser;} else {throw new RuntimeException("创建用户失败");}}String token = jwtUtil.generateToken(openId);return WxLoginVO.builder().token(token).user(wxUser).build();}

其余接口中如果想从请求头获取wxUser信息,只需要在接口中加入注解:

@RequestAttribute("wxUser") WxUser user

示例:

 @DeleteMapping("/delReceiveAddress")public AjaxResult delReceiveAddress(Long id, @RequestAttribute("wxUser") WxUser user) {return toAjax(authService.delReceiveAddress(id, user));}

尾部:
@RequestAttribute(“wxUser”) :会自动从拦截器中获取用户信息。因为拦截器中设置了:request.setAttribute(“wxUser”, wxUser),Spring 会自动将该属性注入到方法参数中,无需手动从 request 取。使用该注解可以优雅的取出用户信息

补充新版本依赖和JwtUtil:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>

JwtUtil工具类:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** JWT 工具类:用于生成和解析 Token*/
public class JwtUtil {// 令牌秘钥@Value("${token.secret}")private String SECRET_KEY;private static final long EXPIRATION_TIME = 1000L * 60 * 60 * 24 * 7; // 7 天,单位毫秒private static final Key key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());/*** 生成 Token* @param openId 用户唯一标识(如微信 openid)* @return JWT Token 字符串*/public static String generateToken(String openId) {Map<String, Object> claims = new HashMap<>();claims.put("openId", openId); // 可以放一些自定义 claimsreturn Jwts.builder().setClaims(claims).setSubject(openId).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).signWith(key, SignatureAlgorithm.HS256).compact();}/*** 从 Token 中获取 openid(可扩展获取其他信息)* @param token JWT Token* @return openid*/public static String getOpenIdFromToken(String token) {return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody().getSubject();}
}
http://www.dtcms.com/a/341085.html

相关文章:

  • shell间接引用
  • CVE-2018-12613 漏洞复现
  • 为什么我的UI界面会突然卡顿,失去响应
  • FLASK项目快速构建
  • 用TestComplete打造高效CI/CD测试流程
  • nodejs mongodb基础
  • 【论文阅读】-《SIGN-OPT: A QUERY-EFFICIENT HARD-LABEL ADVERSARIAL ATTACK》
  • Gitea Webhook教程:实现git push后自动部署更新网站 (CI/CD入门)
  • 7.2 Linux:驱动开发——模块机制
  • 7.3 Linux:驱动开发——应用程序和驱动程序的交互
  • imx6ull-驱动开发篇30——Linux 非阻塞IO实验
  • 电商平台商品详情数据爬取教程​
  • JS原型链
  • 第10课_Rust网络编程
  • TrustZone 版的按键点灯程序下载调试 LAT1492
  • 迅为RK3562开发板Android修改uboot logo
  • element UI 和 element plus 在组件上有哪些不同
  • 《算法导论》第 35 章-近似算法
  • 《设计模式之禅》笔记摘录 - 17.模板方法模式
  • hot100 之160-相交链表(双指针切换)
  • 如何合并分卷压缩文件?两种方法让文件更整洁
  • SQL详细语法教程(七)核心优化
  • 【CocosCreator】electron/Cocos双窗口本地模拟聊天系统
  • 挑战极限:在256MB内存的机器上构建MySQL极简安装方案
  • Nginx 负载均衡和缓存配置
  • Unicode 字符串转 UTF-8 编码算法剖析
  • FPGA实现Aurora 64B66B图像视频点对点传输,基于GTH高速收发器,提供2套工程源码和技术支持
  • 科研笔记:博士论文写作攻略
  • IPSEC安全基础前篇
  • 七十三、【Linux数据库】MySQL数据库PXC 集群概述与演示