提交 20917120 编写于 作者: H haoxr

feat:微信小程序登录认证

上级 05399119
......@@ -107,6 +107,12 @@
<artifactId>common-rabbitmq</artifactId>
</dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
</dependencies>
<build>
......
......@@ -41,7 +41,7 @@ public class RabbitMQConfig {
// 延时队列的消息过期了,会自动触发消息的转发,根据routingKey发送到指定的exchange中,exchange路由到死信队列
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "order.exchange");
args.put("x-dead-letter-routing-key", "order:close"); // 死信路由Key
args.put("x-dead-letter-routing-key", "order.close"); // 死信路由Key
args.put("x-message-ttl", 60000); // 单位:毫秒,1分钟测试使用
return new Queue("order.delay.queue", true, false, false, args);
}
......@@ -66,11 +66,11 @@ public class RabbitMQConfig {
/**
* 死信队列绑定交换机
* 其中死信路由的routingKey=order:close和延时队列的routingKey一致,延时队列过期时将消息发送给exchange,exchange再路由到死信队列
* 其中死信路由的routingKey=order.close和延时队列的routingKey一致,延时队列过期时将消息发送给exchange,exchange再路由到死信队列
*/
@Bean
public Binding closeOrderQueueBinding() {
return new Binding("order.close.queue", Binding.DestinationType.QUEUE,"order.exchange","order:close",null);
return new Binding("order.close.queue", Binding.DestinationType.QUEUE,"order.exchange","order.close",null);
}
}
......@@ -30,7 +30,7 @@ import java.util.Optional;
* @date 2020-12-30 22:31:10
*/
@Api(tags = "【系统管理】订单服务")
@RestController("V1-OrderController")
@RestController("AdminOrderController")
@RequestMapping("/api/v1/orders")
@Slf4j
@AllArgsConstructor
......
......@@ -30,7 +30,7 @@ public interface SkuFeignClient {
Result<Boolean> unlockStock(@RequestParam String orderToken);
@PutMapping("/v2/skus/deduct_stock")
@PutMapping("/app-api/v1/skus/deduct_stock")
Result deductStock(@RequestParam String orderToken);
......
......@@ -102,7 +102,8 @@
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-es</artifactId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
<dependency>
......
package com.youlai.mall.pms.controller.app;
import com.youlai.common.elasticsearch.service.ElasticSearchService;
import com.youlai.common.result.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
......@@ -21,8 +20,6 @@ import org.springframework.web.bind.annotation.*;
@AllArgsConstructor
public class SearchController {
private ElasticSearchService elasticSearchService;
@ApiOperation(value = "关键字搜索商品")
@ApiImplicitParams({
@ApiImplicitParam(name = "key", value = "关键字", paramType = "query", dataType = "String"),
......
......@@ -41,15 +41,15 @@ public class SmsSeckillSession implements Serializable {
/**
* 创建时间
*/
private Date gmtCreate;
private Date createTime;
/**
* 修改时间
*/
private Date gmtModified;
private Date updateTime;
@TableField(exist = false)
private List<SmsSeckillSkuRelation> relations;
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
}
......@@ -16,7 +16,7 @@ import java.util.List;
@Api(tags = "【移动端】营销广告")
@RestController("APPAdvertController")
@RequestMapping("/api-app/v1/adverts")
@RequestMapping("/app-api/v1/adverts")
@Slf4j
@AllArgsConstructor
public class AdvertController {
......
......@@ -15,11 +15,11 @@ public interface MemberAddressFeignClient {
/**
* 获取地址详情
*/
@GetMapping("/v1/addresses/{id}")
@GetMapping("/app-api/v1/addresses/{id}")
Result<UmsAddress> getById(@PathVariable("id") Long id);
@GetMapping("/v1/addresses")
@GetMapping("/app-api/v1/addresses")
Result<List<UmsAddress>> list(@RequestParam Long memberId);
}
......
......@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*;
public interface MemberFeignClient {
@PostMapping("/app-api/v1/members")
Result<UmsMember> add(@RequestBody UmsMember member);
Result<Long > add(@RequestBody UmsMember member);
@PutMapping("/app-api/v1/members/{id}")
......
......@@ -14,4 +14,5 @@ public class MemberDTO {
private String mobile;
private Long balance;
}
......@@ -61,10 +61,10 @@ public class MemberController {
@ApiOperation(value = "新增会员")
@ApiImplicitParam(name = "member", value = "实体JSON对象", required = true, paramType = "body", dataType = "UmsMember")
@PostMapping
public Result<UmsMember> add(@RequestBody UmsMember member) {
public Result<Long> add(@RequestBody UmsMember member) {
boolean status = iUmsMemberService.save(member);
if (status) {
return Result.success(member);
return Result.success(member.getId());
} else {
return Result.failed();
}
......@@ -78,7 +78,7 @@ public class MemberController {
return Result.judge(status);
}
@ApiOperation(value = "获取当前请求的会员信息")
@ApiOperation(value = "获取登录会员信息")
@GetMapping("/me")
public Result getMemberInfo() {
Long userId = JwtUtils.getUserId();
......
......@@ -4,7 +4,9 @@ import cn.hutool.json.JSONObject;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.youlai.auth.common.enums.OAuthClientEnum;
import com.youlai.auth.service.impl.WeAppServiceImpl;
import com.youlai.auth.domain.OAuthToken;
import com.youlai.auth.domain.UserInfo;
import com.youlai.auth.service.IAuthService;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.result.Result;
import com.youlai.common.web.util.JwtUtils;
......@@ -34,7 +36,7 @@ import java.util.concurrent.TimeUnit;
public class OAuthController {
private TokenEndpoint tokenEndpoint;
private WeAppServiceImpl weAppServiceImpl;
private IAuthService wechatAuthService;
private RedisTemplate redisTemplate;
private KeyPair keyPair;
......@@ -63,8 +65,6 @@ public class OAuthController {
String clientId = JwtUtils.getAuthClientId();
OAuthClientEnum client = OAuthClientEnum.getByClientId(clientId);
switch (client) {
case WEAPP: // 微信小程序
return Result.success(weAppServiceImpl.login(parameters));
case TEST: // knife4j接口测试文档使用 client_id/client_secret : client/123456
return tokenEndpoint.postAccessToken(principal, parameters).getBody();
default:
......@@ -72,6 +72,14 @@ public class OAuthController {
}
}
@ApiOperation(value = "微信登录")
@PostMapping("/token/{code}")
public Result wechatLogin(@PathVariable String code, @RequestBody UserInfo userInfo) {
OAuthToken token = wechatAuthService.login(code, userInfo);
return Result.success(token);
}
@ApiOperation(value = "注销", notes = "logout")
@DeleteMapping("/logout")
public Result logout() {
......
package com.youlai.auth.domain;
import com.youlai.auth.common.jwt.JwtPayloadBuilder;
import lombok.*;
import java.util.Set;
/**
* 描述: [类型描述]
* 描述: [自定义token]
* 创建时间: 2021/6/8
*
* @author hxr
* @version 1.0.0
* @update [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
*/
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class OAuthToken {
private String access_token;
private String token_type = "bearer";
public OAuthToken accessToken(String accessToken) {
this.access_token = accessToken;
return this;
}
public OAuthToken tokenType(String tokenType) {
this.token_type = tokenType;
return this;
}
}
package com.youlai.auth.service;
import com.youlai.auth.domain.OAuthToken;
import com.youlai.auth.domain.UserInfo;
import java.util.Map;
/**
......@@ -12,5 +15,5 @@ import java.util.Map;
*/
public interface IAuthService {
Map<String,Object> login(Map<String, String> parameters);
OAuthToken login(String code, UserInfo userInfo);
}
package com.youlai.auth.service.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.youlai.auth.common.jwt.JwtGenerator;
import com.youlai.auth.domain.UserInfo;
import com.youlai.auth.service.IAuthService;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.result.Result;
import com.youlai.common.result.ResultCode;
import com.youlai.common.web.exception.BizException;
import com.youlai.mall.ums.api.MemberFeignClient;
import com.youlai.mall.ums.pojo.domain.UmsMember;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author haoxr
* @description 微信小程序认证接口
* @createTime 2021/5/20 23:37
*/
@Service
@AllArgsConstructor
public class WeAppServiceImpl implements IAuthService {
private MemberFeignClient memberFeignClient;
private WxMaService wxMaService;
private JwtGenerator jwtGenerator;
/**
* @param parameters code=小程序授权code
* rawData=不包括敏感信息的原始数据字符串,用于计算签名
* signature=使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息,详见 用户数据的签名验证和加解密
* @return
*/
@SneakyThrows
@Override
public Map<String, Object> login(Map<String, String> parameters) {
Map<String, Object> resultMap = new HashMap<>();
String code = parameters.get("code");
String rawData = parameters.get("rawData");
String signature = parameters.get("signature");
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
String sessionKey = sessionInfo.getSessionKey();
// 校验微信用户信息
boolean checkResult = wxMaService.getUserService().checkUserInfo(sessionKey, rawData, signature);
if (checkResult) {
String openid = sessionInfo.getOpenid();
Result<UmsMember> result = memberFeignClient.getByOpenid(openid);
UmsMember member = null;
Result memberOptResult = null;
if (ResultCode.USER_NOT_EXIST.getCode().equals(result.getCode())) {
// 用户不存在,注册成为新用户
UserInfo userInfo = JSONUtil.toBean(rawData, UserInfo.class);
member = new UmsMember();
BeanUtil.copyProperties(userInfo, member);
member.setOpenid(openid);
member.setSessionKey(sessionKey);
memberOptResult = memberFeignClient.add(member);
if (ResultCode.SUCCESS.getCode().equals(memberOptResult.getCode())) {
member = (UmsMember) memberOptResult.getData();
}
} else if (ResultCode.SUCCESS.getCode().equals(result.getCode()) && result.getData() != null) {
member = result.getData();
UserInfo userInfo = JSONUtil.toBean(rawData, UserInfo.class);
BeanUtil.copyProperties(userInfo, member);
member.setSessionKey(sessionKey);
memberOptResult = memberFeignClient.update(member.getId(), member);
}
if (memberOptResult != null && ResultCode.SUCCESS.getCode().equals(memberOptResult.getCode())) {
// JWT授权,一般存放用户的角色标识,用于资源服务器(网关)鉴权
Set<String> authorities = new HashSet<>();
// JWT增强,携带用户ID等信息
Map<String, String> additional = new HashMap<>();
additional.put(AuthConstants.USER_ID_KEY, Convert.toStr(member.getId()));
String accessToken = jwtGenerator.createAccessToken(authorities, additional);
String tokenType = "bearer";
resultMap.put("access_token", accessToken);
resultMap.put("token_type", tokenType);
return resultMap;
}
} else {
throw new BizException("非法用户");
}
throw new BizException("认证失败");
}
}
package com.youlai.auth.service.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.youlai.auth.common.jwt.JwtGenerator;
import com.youlai.auth.domain.OAuthToken;
import com.youlai.auth.domain.UserInfo;
import com.youlai.auth.service.IAuthService;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.result.Result;
import com.youlai.common.result.ResultCode;
import com.youlai.mall.ums.api.MemberFeignClient;
import com.youlai.mall.ums.pojo.domain.UmsMember;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author haoxr
* @description 微信小程序认证接口
* @createTime 2021/5/20 23:37
*/
@Service
@AllArgsConstructor
public class WechatAuthServiceImpl implements IAuthService {
private MemberFeignClient memberFeignClient;
private WxMaService wxMaService;
private JwtGenerator jwtGenerator;
@SneakyThrows
@Override
public OAuthToken login(String code, UserInfo userInfo) {
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
String openid = sessionInfo.getOpenid();
Result<UmsMember> result = memberFeignClient.getByOpenid(openid);
UmsMember member;
if (ResultCode.USER_NOT_EXIST.getCode().equals(result.getCode())) {
// 用户不存在,注册成为新用户
member = new UmsMember();
BeanUtil.copyProperties(userInfo, member);
member.setOpenid(openid);
Result<Long> addRes = memberFeignClient.add(member);
Assert.isTrue(ResultCode.SUCCESS.getCode().equals(addRes.getCode()), "微信用户注册失败");
member.setId(addRes.getData()); // 新增后有了会员ID
} else {
member = result.getData();
}
// 自定义JWT生成
// 1. JWT授权,一般存放用户的角色标识,用于资源服务器(网关)鉴权
Set<String> authorities = new HashSet<>();
// 2. JWT增强,携带用户ID等信息
Map<String, String> additional = new HashMap<>();
additional.put(AuthConstants.USER_ID_KEY, Convert.toStr(member.getId()));
String accessToken = jwtGenerator.createAccessToken(authorities, additional);
OAuthToken token = new OAuthToken().accessToken(accessToken);
return token;
}
}
......@@ -40,7 +40,8 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
ServerHttpRequest request = authorizationContext.getExchange().getRequest();
// Restful接口权限设计 @link https://www.cnblogs.com/haoxianrui/p/14396990.html
String restPath = request.getMethodValue() + "_" + request.getURI().getPath();
String restfulPath = request.getMethodValue() + "_" + request.getURI().getPath();
log.info("restful path:{}",restfulPath);
PathMatcher pathMatcher = new AntPathMatcher();
// 对应跨域的预检请求直接放行
if (request.getMethod() == HttpMethod.OPTIONS) {
......@@ -52,7 +53,7 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
boolean needCheck = false; // 是否被设置需要鉴权
for (Map.Entry<String, Object> permRoles : permRolesRule.entrySet()) {
String perm = permRoles.getKey(); // URL权限标识
if (pathMatcher.match(perm, restPath)) {
if (pathMatcher.match(perm, restfulPath)) {
List<String> roles = Convert.toList(String.class, permRoles.getValue());
hasPermRoles.addAll(Convert.toList(String.class, roles));
needCheck = true;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册