feat(auth): 添加微信登录功能- 新增微信登录相关配置和接口
- 实现微信登录逻辑,包括获取 openid 和 session_key- 更新安全配置,允许微信登录请求通过 - 添加必要的依赖和数据传输对象
This commit is contained in:
parent
1e4d0abd3a
commit
ae619cc964
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.example.admin_server.controller.client;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/client/customer")
|
||||||
|
public class CustomerController {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
package com.example.admin_server.controller.client;
|
package com.example.admin_server.controller.client;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.example.admin_server.common.Result;
|
import com.example.admin_server.common.Result;
|
||||||
import com.example.admin_server.config.WxConfig;
|
import com.example.admin_server.config.WxConfig;
|
||||||
import com.example.admin_server.model.dto.WxLoginDTO;
|
import com.example.admin_server.model.dto.WxLoginDTO;
|
||||||
|
import com.example.admin_server.model.entity.Customer;
|
||||||
|
import com.example.admin_server.service.ICustomerService;
|
||||||
|
import com.example.admin_server.utils.JwtUtil;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
@ -13,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -23,6 +28,8 @@ import java.util.Map;
|
||||||
public class WxLoginController {
|
public class WxLoginController {
|
||||||
|
|
||||||
private final WxConfig wxConfig;
|
private final WxConfig wxConfig;
|
||||||
|
private final ICustomerService iCustomerService;
|
||||||
|
private final JwtUtil jwtUtil;
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@ApiOperation(value = "微信登录")
|
@ApiOperation(value = "微信登录")
|
||||||
|
|
@ -32,32 +39,58 @@ public class WxLoginController {
|
||||||
return Result.fail("code 参数不能为空");
|
return Result.fail("code 参数不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造请求微信的 URL
|
// 请求微信接口
|
||||||
String url = wxConfig.getJscode2sessionUrl()
|
String url = wxConfig.getJscode2sessionUrl()
|
||||||
+ "?appid=" + wxConfig.getAppid()
|
+ "?appid=" + wxConfig.getAppid()
|
||||||
+ "&secret=" + wxConfig.getSecret()
|
+ "&secret=" + wxConfig.getSecret()
|
||||||
+ "&js_code=" + code
|
+ "&js_code=" + code
|
||||||
+ "&grant_type=authorization_code";
|
+ "&grant_type=authorization_code";
|
||||||
|
|
||||||
// 请求微信服务器
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
String response = restTemplate.getForObject(url, String.class);
|
String response = restTemplate.getForObject(url, String.class);
|
||||||
|
|
||||||
// 解析微信响应
|
|
||||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||||
|
System.out.println(jsonObject);
|
||||||
String openid = jsonObject.getString("openid");
|
String openid = jsonObject.getString("openid");
|
||||||
String sessionKey = jsonObject.getString("session_key");
|
String sessionKey = jsonObject.getString("session_key");
|
||||||
|
String unionid = jsonObject.getString("unionid");
|
||||||
|
|
||||||
if (openid == null) {
|
if (openid == null) {
|
||||||
String errMsg = jsonObject.getString("errmsg");
|
return Result.fail("微信登录失败: " + jsonObject.getString("errmsg"));
|
||||||
return Result.fail("微信登录失败: " + errMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 你可以在这里用 openid 查数据库,创建或更新用户,生成 JWT 等
|
// 查找用户是否已存在
|
||||||
|
Customer customer = iCustomerService.getOne(new QueryWrapper<Customer>().eq("openid", openid));
|
||||||
|
|
||||||
|
if (customer == null) {
|
||||||
|
// 创建新用户
|
||||||
|
customer = new Customer()
|
||||||
|
.setOpenid(openid)
|
||||||
|
.setSessionKey(sessionKey)
|
||||||
|
.setUnionid(unionid)
|
||||||
|
.setNickname("微信用户") // 默认昵称,可后续完善
|
||||||
|
.setAvatarUrl(null)
|
||||||
|
.setCreateTime(LocalDateTime.now())
|
||||||
|
.setUpdateTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
iCustomerService.save(customer);
|
||||||
|
} else {
|
||||||
|
// 更新 session_key 与 update_time
|
||||||
|
customer.setSessionKey(sessionKey);
|
||||||
|
customer.setUpdateTime(LocalDateTime.now());
|
||||||
|
iCustomerService.updateById(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> claims = new HashMap<>();
|
||||||
|
claims.put("id", customer.getId());
|
||||||
|
claims.put("username", customer.getUsername());
|
||||||
|
claims.put("sessionKey", customer.getSessionKey());
|
||||||
|
claims.put("openid", customer.getOpenid());
|
||||||
|
String token = jwtUtil.generateToken(claims);
|
||||||
Map<String, Object> resultData = new HashMap<>();
|
Map<String, Object> resultData = new HashMap<>();
|
||||||
|
resultData.put("token", token);
|
||||||
resultData.put("openid", openid);
|
resultData.put("openid", openid);
|
||||||
resultData.put("token", "mock-token-" + openid); // 后期你可以用 JWT 替换这里
|
resultData.put("nickname", customer.getNickname());
|
||||||
|
resultData.put("avatar", customer.getAvatarUrl());
|
||||||
|
|
||||||
return Result.ok("登录成功", resultData);
|
return Result.ok("登录成功", resultData);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.admin_server.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.example.admin_server.model.entity.Customer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
public interface CustomerMapper extends BaseMapper<Customer> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.example.admin_server.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("customer")
|
||||||
|
@ApiModel(value="Customer对象", description="客户表")
|
||||||
|
public class Customer implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "主键ID")
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "微信openid")
|
||||||
|
@TableField("openid")
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "微信会话密钥(可选存储)")
|
||||||
|
@TableField("session_key")
|
||||||
|
private String sessionKey;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "微信unionid(如果获取到)")
|
||||||
|
@TableField("unionid")
|
||||||
|
private String unionid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户名")
|
||||||
|
@TableField("username")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "密码")
|
||||||
|
@TableField("password")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户昵称")
|
||||||
|
@TableField("nickname")
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "头像URL")
|
||||||
|
@TableField("avatar_url")
|
||||||
|
private String avatarUrl;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "邮箱")
|
||||||
|
@TableField("email")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号(后续绑定时)")
|
||||||
|
@TableField("phone")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间")
|
||||||
|
@TableField("create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "更新时间")
|
||||||
|
@TableField("update_time")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.admin_server.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.example.admin_server.model.entity.Customer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
public interface ICustomerService extends IService<Customer> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.example.admin_server.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.example.admin_server.mapper.CustomerMapper;
|
||||||
|
import com.example.admin_server.model.entity.Customer;
|
||||||
|
import com.example.admin_server.service.ICustomerService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author FallingCliff
|
||||||
|
* @since 2025-05-24
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements ICustomerService {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.example.admin_server.mapper.CustomerMapper">
|
||||||
|
|
||||||
|
<!-- 通用查询映射结果 -->
|
||||||
|
<resultMap id="BaseResultMap" type="com.example.admin_server.model.entity.Customer">
|
||||||
|
<id column="id" property="id" />
|
||||||
|
<result column="openid" property="openid" />
|
||||||
|
<result column="session_key" property="sessionKey" />
|
||||||
|
<result column="unionid" property="unionid" />
|
||||||
|
<result column="username" property="username" />
|
||||||
|
<result column="password" property="password" />
|
||||||
|
<result column="nickname" property="nickname" />
|
||||||
|
<result column="avatar_url" property="avatarUrl" />
|
||||||
|
<result column="email" property="email" />
|
||||||
|
<result column="phone" property="phone" />
|
||||||
|
<result column="create_time" property="createTime" />
|
||||||
|
<result column="update_time" property="updateTime" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue