- 后端:更新 README
- 后端:重构部分代码
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
package cn.iocoder.mall.user.application.controller.users;
|
||||
|
||||
import cn.iocoder.common.framework.constant.UserTypeEnum;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RefreshTokenDTO;
|
||||
import cn.iocoder.mall.user.api.MobileCodeService;
|
||||
import cn.iocoder.mall.user.api.OAuth2Service;
|
||||
import cn.iocoder.mall.user.api.UserService;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
|
||||
import cn.iocoder.mall.user.api.dto.user.UserAuthenticationByMobileCodeDTO;
|
||||
import cn.iocoder.mall.user.application.convert.PassportConvert;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersAccessTokenVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -26,7 +25,7 @@ import static cn.iocoder.common.framework.vo.CommonResult.success;
|
||||
@Api("Passport 模块")
|
||||
public class PassportController {
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.provider.OAuth2Service.version}")
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version}")
|
||||
private OAuth2Service oauth2Service;
|
||||
@Reference(validation = "true", version = "${dubbo.provider.UserService.version}")
|
||||
private UserService userService;
|
||||
@@ -40,14 +39,12 @@ public class PassportController {
|
||||
// return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
|
||||
// }
|
||||
|
||||
@PermitAll
|
||||
@PostMapping("/mobile/register")
|
||||
@ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建")
|
||||
public CommonResult<UserAuthenticationBO> mobileRegister(UserAuthenticationByMobileCodeDTO userAuthenticationByMobileCodeDTO) {
|
||||
return success(userService.authenticationByMobileCode(userAuthenticationByMobileCodeDTO));
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@PostMapping("mobile/send_register_code")
|
||||
@ApiOperation(value = "发送手机验证码")
|
||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691300")
|
||||
@@ -59,24 +56,21 @@ public class PassportController {
|
||||
// TODO 芋艿,改绑手机号
|
||||
|
||||
// TODO 功能:qq 登陆
|
||||
@PermitAll
|
||||
@PostMapping("/qq/login")
|
||||
public String qqLogin() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO 功能:qq 绑定
|
||||
@PermitAll
|
||||
@PostMapping("/qq/bind")
|
||||
public String qqBind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@PostMapping("/refresh_token") // TODO 功能:刷新 token
|
||||
public CommonResult<UsersAccessTokenVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
OAuth2AccessTokenBO result = oauth2Service.refreshToken(refreshToken);
|
||||
return success(PassportConvert.INSTANCE.convert2(result));
|
||||
public CommonResult<OAuth2AccessTokenBO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
return success(oauth2Service.refreshToken(new OAuth2RefreshTokenDTO().setRefreshToken(refreshToken)
|
||||
.setUserType(UserTypeEnum.USER.getValue())));
|
||||
}
|
||||
|
||||
// TODO 功能:退出,销毁 token
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.iocoder.mall.user.api.bo.UserBO;
|
||||
import cn.iocoder.mall.user.api.dto.UserUpdateDTO;
|
||||
import cn.iocoder.mall.user.application.convert.UserConvert;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersUserVO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.RequiresLogin;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -23,6 +24,7 @@ public class UserController {
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/info")
|
||||
@RequiresLogin
|
||||
@ApiOperation(value = "用户信息")
|
||||
public CommonResult<UsersUserVO> info() {
|
||||
UserBO userResult = userService.getUser(UserSecurityContextHolder.getContext().getUserId());
|
||||
@@ -30,6 +32,7 @@ public class UserController {
|
||||
}
|
||||
|
||||
@PostMapping("/update_avatar")
|
||||
@RequiresLogin
|
||||
@ApiOperation(value = "更新头像")
|
||||
public CommonResult<Boolean> updateAvatar(@RequestParam("avatar") String avatar) {
|
||||
// 创建
|
||||
@@ -40,6 +43,7 @@ public class UserController {
|
||||
}
|
||||
|
||||
@PostMapping("/update_nickname")
|
||||
@RequiresLogin
|
||||
@ApiOperation(value = "更新昵称")
|
||||
public CommonResult<Boolean> updateNickname(@RequestParam("nickname") String nickname) {
|
||||
// 创建
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package cn.iocoder.mall.user.application.convert;
|
||||
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersAccessTokenVO;
|
||||
import cn.iocoder.mall.user.application.vo.users.UsersMobileRegisterVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface PassportConvert {
|
||||
|
||||
PassportConvert INSTANCE = Mappers.getMapper(PassportConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
UsersMobileRegisterVO convert(OAuth2AccessTokenBO oauth2AccessTokenBO);
|
||||
|
||||
@Mappings({})
|
||||
UsersAccessTokenVO convert2(OAuth2AccessTokenBO result);
|
||||
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
@@ -39,13 +41,15 @@ public class UserAddressAddPO implements Serializable {
|
||||
@NotNull(message = "手机号为不能为空!")
|
||||
@Size(min = 11, max = 11, message = "手机号为 11 位!")
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 收件详细地址
|
||||
*/
|
||||
@ApiModelProperty("收件详细地址")
|
||||
@NotNull(message = "详细地址不能为空")
|
||||
@Size(min = 10, max = 100, message = "地址在 10 ~ 100 字之间!")
|
||||
@NotEmpty(message = "详细地址不能为空")
|
||||
@Length(min = 10, max = 100, message = "地址在 10 ~ 100 字之间!")
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 收件详细地址
|
||||
*/
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package cn.iocoder.mall.user.sdk.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* URL 是否允许所有都可访问。即用户不登陆,就可以访问指定 URL 。
|
||||
*
|
||||
* 例如说,注册接口,用户是不需要登陆,就可以访问的。
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // ElementType.TYPE 暂时不支持类级别。为了减少判断,略微提升性能。
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PermitAll {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.iocoder.mall.user.sdk.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 要求用户登录注解。通过将该注解添加到 Controller 上,会自动校验用户是否登陆。
|
||||
*
|
||||
* 默认请求下,用户访问的 API 接口,无需登陆。主要的考虑是,
|
||||
* 1. 需要用户登陆的接口,本身会获取在线用户的编号。如果不添加 @RequiresLogin 注解就会报错。
|
||||
* 2. 大多数情况下,用户的 API 接口无需登陆。
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RequiresLogin {
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
|
||||
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
|
||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||
import cn.iocoder.mall.user.sdk.annotation.RequiresLogin;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContext;
|
||||
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
@@ -49,8 +49,8 @@ public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
// 进行鉴权
|
||||
HandlerMethod method = (HandlerMethod) handler;
|
||||
boolean isPermitAll = method.hasMethodAnnotation(PermitAll.class);
|
||||
if (!isPermitAll) { // 如果需要鉴权
|
||||
boolean requiresLogin = method.hasMethodAnnotation(RequiresLogin.class);
|
||||
if (requiresLogin) { // 如果需要鉴权
|
||||
if (serviceException != null) { // 认证失败,抛出上面认证失败的 ServiceException 异常
|
||||
throw serviceException;
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package cn.iocoder.mall.user.api;
|
||||
|
||||
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
||||
|
||||
@Deprecated
|
||||
public interface OAuth2Service {
|
||||
|
||||
/**
|
||||
* 校验访问令牌,获取身份信息( 不包括 accessToken 等等 )
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @return 授权信息
|
||||
*/
|
||||
OAuth2AuthenticationBO checkToken(String accessToken);
|
||||
|
||||
OAuth2AccessTokenBO refreshToken(String refreshToken);
|
||||
|
||||
// TODO @see 移除 token
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package cn.iocoder.mall.user.api;
|
||||
|
||||
import cn.iocoder.mall.user.api.dto.UserAccessLogAddDTO;
|
||||
|
||||
@Deprecated
|
||||
public interface UserAccessLogService {
|
||||
|
||||
void addUserAccessLog(UserAccessLogAddDTO userAccessLogAddDTO);
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package cn.iocoder.mall.user.api.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AccessTokenBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
private String refreshToken;
|
||||
/**
|
||||
* 过期时间,单位:秒。
|
||||
*/
|
||||
private Integer expiresIn;
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package cn.iocoder.mall.user.api.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2AuthenticationBO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package cn.iocoder.mall.user.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户访问日志添加 DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class UserAccessLogAddDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户编号 - 空
|
||||
*/
|
||||
public static final Integer USER_ID_NULL = 0;
|
||||
|
||||
/**
|
||||
* 用户编号.
|
||||
*
|
||||
* 当用户为空时,该值为0
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Integer userId;
|
||||
/**
|
||||
* 访问地址
|
||||
*/
|
||||
@NotNull(message = "访问地址不能为空")
|
||||
private String uri;
|
||||
/**
|
||||
* 参数
|
||||
*/
|
||||
@NotNull(message = "请求参数不能为空")
|
||||
private String queryString;
|
||||
/**
|
||||
* http 方法
|
||||
*/
|
||||
@NotNull(message = "http 请求方法不能为空")
|
||||
private String method;
|
||||
/**
|
||||
* User Agent
|
||||
*/
|
||||
@NotNull(message = "User-Agent 不能为空")
|
||||
private String userAgent;
|
||||
/**
|
||||
* ip
|
||||
*/
|
||||
@NotNull(message = "ip 不能为空")
|
||||
private String ip;
|
||||
/**
|
||||
* 请求时间
|
||||
*/
|
||||
@NotNull(message = "请求时间不能为空")
|
||||
private Date startTime;
|
||||
/**
|
||||
* 响应时长 -- 毫秒级
|
||||
*/
|
||||
@NotNull(message = "响应时长不能为空")
|
||||
private Integer responseTime;
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2AccessTokenDO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface OAuth2Convert {
|
||||
|
||||
OAuth2Convert INSTANCE = Mappers.getMapper(OAuth2Convert.class);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(source = "id", target = "accessToken")
|
||||
})
|
||||
OAuth2AccessTokenBO convertToAccessToken(OAuth2AccessTokenDO oauth2AccessTokenDO);
|
||||
|
||||
default OAuth2AccessTokenBO convertToAccessTokenWithExpiresIn(OAuth2AccessTokenDO oauth2AccessTokenDO) {
|
||||
return this.convertToAccessToken(oauth2AccessTokenDO)
|
||||
.setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0));
|
||||
}
|
||||
|
||||
@Mappings({})
|
||||
OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO);
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.UserAccessLogDO;
|
||||
import cn.iocoder.mall.user.api.dto.UserAccessLogAddDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface UserAccessLogConvert {
|
||||
|
||||
UserAccessLogConvert INSTANCE = Mappers.getMapper(UserAccessLogConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
UserAccessLogDO convert(UserAccessLogAddDTO adminAccessLogAddDTO);
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2AccessTokenDO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OAuth2AccessTokenMapper {
|
||||
|
||||
void insert(OAuth2AccessTokenDO entity);
|
||||
|
||||
OAuth2AccessTokenDO selectByTokenId(String tokenId);
|
||||
|
||||
void updateToInvalidByUserId(@Param("userId") Integer userId);
|
||||
|
||||
void updateToInvalidByRefreshToken(@Param("refreshToken") String refreshToken);
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2RefreshTokenDO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OAuth2RefreshTokenMapper {
|
||||
|
||||
void insert(OAuth2RefreshTokenDO entity);
|
||||
|
||||
void updateToInvalidByUserId(@Param("userId") Integer userId);
|
||||
|
||||
OAuth2RefreshTokenDO selectById(@Param("id") String id);
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.UserAccessLogDO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserAccessLogMapper {
|
||||
|
||||
void insert(UserAccessLogDO entity);
|
||||
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.service;
|
||||
|
||||
import cn.iocoder.common.framework.exception.ServiceException;
|
||||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.mall.user.api.OAuth2Service;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
||||
import cn.iocoder.mall.user.api.constant.UserErrorCodeEnum;
|
||||
import cn.iocoder.mall.user.biz.convert.OAuth2Convert;
|
||||
import cn.iocoder.mall.user.biz.dao.OAuth2AccessTokenMapper;
|
||||
import cn.iocoder.mall.user.biz.dao.OAuth2RefreshTokenMapper;
|
||||
import cn.iocoder.mall.user.biz.dataobject.MobileCodeDO;
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2AccessTokenDO;
|
||||
import cn.iocoder.mall.user.biz.dataobject.OAuth2RefreshTokenDO;
|
||||
import cn.iocoder.mall.user.biz.dataobject.UserDO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* OAuth2Service ,实现用户授权相关的逻辑
|
||||
*/
|
||||
@Service
|
||||
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.OAuth2Service.version}")
|
||||
public class OAuth2ServiceImpl implements OAuth2Service {
|
||||
|
||||
/**
|
||||
* 访问令牌过期时间,单位:毫秒
|
||||
*/
|
||||
@Value("${modules.oauth2-code-service.access-token-expire-time-millis}")
|
||||
private int accessTokenExpireTimeMillis;
|
||||
/**
|
||||
* 刷新令牌过期时间,单位:毫秒
|
||||
*/
|
||||
@Value("${modules.oauth2-code-service.refresh-token-expire-time-millis}")
|
||||
private int refreshTokenExpireTimeMillis;
|
||||
|
||||
@Autowired
|
||||
private UserServiceImpl userService;
|
||||
@Autowired
|
||||
private MobileCodeServiceImpl mobileCodeService;
|
||||
@Autowired
|
||||
private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
|
||||
@Autowired
|
||||
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
|
||||
|
||||
@Override
|
||||
public OAuth2AuthenticationBO checkToken(String accessToken) throws ServiceException {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByTokenId(accessToken);
|
||||
if (accessTokenDO == null) { // 不存在
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_ACCESS_TOKEN_NOT_FOUND.getCode());
|
||||
}
|
||||
if (accessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_ACCESS_TOKEN_EXPIRED.getCode());
|
||||
}
|
||||
if (!accessTokenDO.getValid()) { // 无效
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_ACCESS_TOKEN_INVALID.getCode());
|
||||
}
|
||||
// 转换返回
|
||||
return OAuth2Convert.INSTANCE.convertToAuthentication(accessTokenDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenBO refreshToken(String refreshToken) {
|
||||
OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectById(refreshToken);
|
||||
// 校验刷新令牌是否合法
|
||||
if (refreshTokenDO == null) { // 不存在
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_NOT_FOUND.getCode());
|
||||
}
|
||||
if (refreshTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_EXPIRED.getCode());
|
||||
}
|
||||
if (!refreshTokenDO.getValid()) { // 无效
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_INVALID.getCode());
|
||||
}
|
||||
// 标记 refreshToken 对应的 accessToken 都不合法
|
||||
oauth2AccessTokenMapper.updateToInvalidByRefreshToken(refreshToken);
|
||||
// 创建访问令牌
|
||||
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(refreshTokenDO.getUserId(), refreshTokenDO.getId());
|
||||
// 转换返回
|
||||
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除用户对应的 Token
|
||||
*
|
||||
* @param userId 管理员编号
|
||||
*/
|
||||
@Transactional
|
||||
public void removeToken(Integer userId) {
|
||||
// 设置 access token 失效
|
||||
oauth2AccessTokenMapper.updateToInvalidByUserId(userId);
|
||||
// 设置 refresh token 失效
|
||||
oauth2RefreshTokenMapper.updateToInvalidByUserId(userId);
|
||||
}
|
||||
|
||||
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer uid, String refreshToken) {
|
||||
OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO().setId(generateAccessToken())
|
||||
.setRefreshToken(refreshToken)
|
||||
.setUserId(uid)
|
||||
.setExpiresTime(new Date(System.currentTimeMillis() + accessTokenExpireTimeMillis))
|
||||
.setValid(true);
|
||||
oauth2AccessTokenMapper.insert(accessToken);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
private OAuth2RefreshTokenDO createOAuth2RefreshToken(Integer uid) {
|
||||
OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setId(generateRefreshToken())
|
||||
.setUserId(uid)
|
||||
.setExpiresTime(new Date(System.currentTimeMillis() + refreshTokenExpireTimeMillis))
|
||||
.setValid(true);
|
||||
oauth2RefreshTokenMapper.insert(refreshToken);
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
private String generateAccessToken() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
private String generateRefreshToken() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package cn.iocoder.mall.user.biz.service;
|
||||
|
||||
import cn.iocoder.common.framework.util.StringUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.user.biz.dao.UserAccessLogMapper;
|
||||
import cn.iocoder.mall.user.biz.dataobject.UserAccessLogDO;
|
||||
import cn.iocoder.mall.user.api.UserAccessLogService;
|
||||
import cn.iocoder.mall.user.api.dto.UserAccessLogAddDTO;
|
||||
import cn.iocoder.mall.user.biz.convert.UserAccessLogConvert;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.UserAccessLogService.version}")
|
||||
public class UserAccessLogServiceImpl implements UserAccessLogService {
|
||||
|
||||
/**
|
||||
* 请求参数最大长度。
|
||||
*/
|
||||
private static final Integer QUERY_STRING_MAX_LENGTH = 4096;
|
||||
/**
|
||||
* 请求地址最大长度。
|
||||
*/
|
||||
private static final Integer URI_MAX_LENGTH = 4096;
|
||||
/**
|
||||
* User-Agent 最大长度。
|
||||
*/
|
||||
private static final Integer USER_AGENT_MAX_LENGTH = 1024;
|
||||
|
||||
@Autowired
|
||||
private UserAccessLogMapper userAccessLogMapper;
|
||||
|
||||
@Override
|
||||
public void addUserAccessLog(UserAccessLogAddDTO userAccessLogAddDTO) {
|
||||
// 创建 UserAccessLogDO
|
||||
UserAccessLogDO accessLog = UserAccessLogConvert.INSTANCE.convert(userAccessLogAddDTO);
|
||||
accessLog.setCreateTime(new Date());
|
||||
// 截取最大长度
|
||||
if (accessLog.getUri().length() > URI_MAX_LENGTH) {
|
||||
accessLog.setUri(StringUtil.substring(accessLog.getUri(), URI_MAX_LENGTH));
|
||||
}
|
||||
if (accessLog.getQueryString().length() > QUERY_STRING_MAX_LENGTH) {
|
||||
accessLog.setQueryString(StringUtil.substring(accessLog.getQueryString(), QUERY_STRING_MAX_LENGTH));
|
||||
}
|
||||
if (accessLog.getUserAgent().length() > USER_AGENT_MAX_LENGTH) {
|
||||
accessLog.setUserAgent(StringUtil.substring(accessLog.getUserAgent(), USER_AGENT_MAX_LENGTH));
|
||||
}
|
||||
// 插入
|
||||
userAccessLogMapper.insert(accessLog);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import cn.iocoder.common.framework.util.ValidationUtil;
|
||||
import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
|
||||
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2RemoveTokenByUserDTO;
|
||||
import cn.iocoder.mall.user.api.UserService;
|
||||
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
|
||||
import cn.iocoder.mall.user.api.bo.UserBO;
|
||||
@@ -155,7 +156,7 @@ public class UserServiceImpl implements UserService {
|
||||
userMapper.update(updateUser);
|
||||
// 如果是关闭管理员,则标记 token 失效。否则,管理员还可以继续蹦跶
|
||||
if (CommonStatusEnum.DISABLE.getValue().equals(status)) {
|
||||
oAuth2Service.removeToken(userId);
|
||||
oAuth2Service.removeToken(new OAuth2RemoveTokenByUserDTO().setUserId(userId).setUserType(UserTypeEnum.USER.getValue()));
|
||||
}
|
||||
// 返回成功
|
||||
return true;
|
||||
|
||||
@@ -3,6 +3,3 @@
|
||||
modules.mobile-code-service.code-expire-time-millis = 600000
|
||||
modules.mobile-code-service.send-maximum-quantity-per-day = 10
|
||||
modules.mobile-code-service.send-frequency = 60000
|
||||
## OAuth2CodeService
|
||||
modules.oauth2-code-service.access-token-expire-time-millis = 2880000
|
||||
modules.oauth2-code-service.refresh-token-expire-time-millis = 43200000
|
||||
@@ -33,8 +33,6 @@ dubbo:
|
||||
filter: -exception
|
||||
MobileCodeService:
|
||||
version: 1.0.0
|
||||
OAuth2Service:
|
||||
version: 1.0.0
|
||||
UserAccessLogService:
|
||||
version: 1.0.0
|
||||
UserAddressService:
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<?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="cn.iocoder.mall.user.biz.dao.OAuth2AccessTokenMapper">
|
||||
|
||||
<insert id="insert" parameterType="OAuth2AccessTokenDO">
|
||||
INSERT INTO oauth2_access_token (
|
||||
id, refresh_token, user_id, valid, expires_time,
|
||||
create_time
|
||||
) VALUES (
|
||||
#{id}, #{refreshToken}, #{userId}, #{valid}, #{expiresTime},
|
||||
#{createTime}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<select id="selectByTokenId" parameterType="String" resultType="OAuth2AccessTokenDO">
|
||||
SELECT
|
||||
id, user_id, valid, expires_time
|
||||
FROM oauth2_access_token
|
||||
WHERE id = #{id}
|
||||
</select>
|
||||
|
||||
<update id="updateToInvalidByUserId" parameterType="Integer">
|
||||
UPDATE oauth2_access_token
|
||||
SET valid = 0
|
||||
WHERE user_id = #{userId}
|
||||
AND valid = 1
|
||||
</update>
|
||||
|
||||
<update id="updateToInvalidByRefreshToken" parameterType="String">
|
||||
UPDATE oauth2_access_token
|
||||
SET valid = 0
|
||||
WHERE refresh_token = #{refreshToken}
|
||||
AND valid = 1
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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="cn.iocoder.mall.user.biz.dao.OAuth2RefreshTokenMapper">
|
||||
|
||||
<insert id="insert" parameterType="OAuth2RefreshTokenDO">
|
||||
INSERT INTO oauth2_refresh_token (
|
||||
id, user_id, valid, expires_time, create_time
|
||||
) VALUES (
|
||||
#{id}, #{userId}, #{valid}, #{expiresTime}, #{createTime}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateToInvalidByUserId" parameterType="Integer">
|
||||
UPDATE oauth2_refresh_token
|
||||
SET valid = 0
|
||||
WHERE user_id = #{userId}
|
||||
AND valid = 1
|
||||
</update>
|
||||
|
||||
<select id="selectById" parameterType="string" resultType="cn.iocoder.mall.user.biz.dataobject.OAuth2RefreshTokenDO">
|
||||
SELECT
|
||||
id, user_id, valid, expires_time, create_time
|
||||
FROM oauth2_refresh_token
|
||||
WHERE id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?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="cn.iocoder.mall.user.biz.dao.UserAccessLogMapper">
|
||||
|
||||
<!--<sql id="FIELDS">-->
|
||||
<!--id, username, nickname, password, status,-->
|
||||
<!--create_time-->
|
||||
<!--</sql>-->
|
||||
|
||||
<insert id="insert" parameterType="UserAccessLogDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
|
||||
INSERT INTO user_access_log (
|
||||
user_id, uri, query_string, method, user_agent,
|
||||
ip, start_time, response_time, create_time
|
||||
) VALUES (
|
||||
#{userId}, #{uri}, #{queryString}, #{method}, #{userAgent},
|
||||
#{ip}, #{startTime}, #{responseTime}, #{createTime}
|
||||
)
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user