增加管理员模块~

This commit is contained in:
YunaiV
2019-02-27 00:00:37 +08:00
parent e431530107
commit 09004dc000
65 changed files with 1929 additions and 104 deletions

View File

@@ -1,7 +1,7 @@
package cn.iocoder.mall.user.config;
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
import cn.iocoder.mall.user.sdk.interceptor.SecurityInterceptor;
import cn.iocoder.mall.user.sdk.interceptor.UserSecurityInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -13,11 +13,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@EnableWebMvc
@Configuration
@Import(value = {GlobalExceptionHandler.class, // 统一全局返回
SecurityInterceptor.class}) // 安全拦截器,实现认证和授权功能。
UserSecurityInterceptor.class}) // 安全拦截器,实现认证和授权功能。
public class MVCConfiguration implements WebMvcConfigurer {
@Autowired
private SecurityInterceptor securityInterceptor;
private UserSecurityInterceptor securityInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {

View File

@@ -46,7 +46,7 @@ public class PassportController {
})
public CommonResult<MobileRegisterVO> mobileRegister(@RequestParam("mobile") String mobile,
@RequestParam("code") String code) {
CommonResult<OAuth2AccessTokenBO> result = oauth2Service.getAccessToken2(mobile, code);
CommonResult<OAuth2AccessTokenBO> result = oauth2Service.getAccessToken(mobile, code);
return PassportConvert.INSTANCE.convert(result);
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.mall.user.controller;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.user.sdk.context.SecurityContextHolder;
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
import cn.iocoder.mall.user.vo.UserInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -18,7 +18,7 @@ public class UserController {
@ApiOperation(value = "用户信息")
public CommonResult<UserInfoVO> info() {
// TODO 芋艿,正在实现中
UserInfoVO user = new UserInfoVO().setId(SecurityContextHolder.getContext().getUid());
UserInfoVO user = new UserInfoVO().setId(UserSecurityContextHolder.getContext().getUid());
return CommonResult.success(user);
}

View File

@@ -1,13 +1,13 @@
package cn.iocoder.mall.user.sdk.context;
/**
* Security 上下文
* User Security 上下文
*/
public class SecurityContext {
public class UserSecurityContext {
private final Long uid;
public SecurityContext(Long uid) {
public UserSecurityContext(Long uid) {
this.uid = uid;
}

View File

@@ -1,23 +1,23 @@
package cn.iocoder.mall.user.sdk.context;
/**
* {@link SecurityContext} Holder
* {@link UserSecurityContext} Holder
*
* 参考 spring security ThreadLocalSecurityContextHolderStrategy 简单实现
*/
public class SecurityContextHolder {
public class UserSecurityContextHolder {
private static final ThreadLocal<SecurityContext> securityContext = new ThreadLocal<SecurityContext>();
private static final ThreadLocal<UserSecurityContext> securityContext = new ThreadLocal<UserSecurityContext>();
public static void setContext(SecurityContext context) {
public static void setContext(UserSecurityContext context) {
securityContext.set(context);
}
public static SecurityContext getContext() {
SecurityContext ctx = securityContext.get();
public static UserSecurityContext getContext() {
UserSecurityContext ctx = securityContext.get();
// 为空时设置一个空的进去
if (ctx == null) {
ctx = new SecurityContext(null);
ctx = new UserSecurityContext(null);
securityContext.set(ctx);
}
return ctx;

View File

@@ -1,15 +1,15 @@
package cn.iocoder.mall.user.sdk.interceptor;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
import cn.iocoder.mall.user.sdk.context.SecurityContext;
import cn.iocoder.mall.user.sdk.context.SecurityContextHolder;
import cn.iocoder.mall.user.sdk.context.UserSecurityContext;
import cn.iocoder.mall.user.sdk.context.UserSecurityContextHolder;
import cn.iocoder.mall.user.service.api.OAuth2Service;
import cn.iocoder.mall.user.service.api.bo.OAuth2AuthenticationBO;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -21,7 +21,7 @@ import javax.servlet.http.HttpServletResponse;
* 安全拦截器
*/
@Component
public class SecurityInterceptor extends HandlerInterceptorAdapter {
public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
@Reference
private OAuth2Service oauth2Service;
@@ -29,7 +29,7 @@ public class SecurityInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 校验访问令牌是否正确若正确返回授权信息
String accessToken = obtainAccess(request);
String accessToken = HttpUtil.obtainAccess(request);
OAuth2AuthenticationBO authentication = null;
if (accessToken != null) {
CommonResult<OAuth2AuthenticationBO> result = oauth2Service.checkToken(accessToken);
@@ -38,8 +38,8 @@ public class SecurityInterceptor extends HandlerInterceptorAdapter {
}
authentication = result.getData();
// 添加到 SecurityContext
SecurityContext context = new SecurityContext(authentication.getUid());
SecurityContextHolder.setContext(context);
UserSecurityContext context = new UserSecurityContext(authentication.getUid());
UserSecurityContextHolder.setContext(context);
}
// 校验是否需要已授权
HandlerMethod method = (HandlerMethod) handler;
@@ -53,19 +53,7 @@ public class SecurityInterceptor extends HandlerInterceptorAdapter {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 清空 SecurityContext
SecurityContextHolder.clear();
}
private String obtainAccess(HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
if (!StringUtils.hasText(authorization)) {
return null;
}
int index = authorization.indexOf("Bearer ");
if (index == -1) { // 未找到
return null;
}
return authorization.substring(index + 7).trim();
UserSecurityContextHolder.clear();
}
}

View File

@@ -1,6 +1,6 @@
/**
* 提供 SDK 给其它服务,使用如下功能:
*
* 1. 通过 {@link } 拦截器,
* 1. 通过 {@link cn.iocoder.mall.user.sdk.interceptor.UserSecurityInterceptor} 拦截器,实现需要登陆 URL 的鉴权
*/
package cn.iocoder.mall.user.sdk;

View File

@@ -1,27 +1,13 @@
package cn.iocoder.mall.user.service.api;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.user.service.api.bo.OAuth2AccessTokenBO;
import cn.iocoder.mall.user.service.api.bo.OAuth2AuthenticationBO;
public interface OAuth2Service {
/**
* 使用手机号 + 验证码,获取访问令牌等信息
*
* 如果手机未注册,并且验证码正确,进行自动注册。
*
* @param mobile 手机号
* @param code 验证码
* @return 授权信息
*/
@Deprecated
OAuth2AccessTokenBO getAccessToken(String mobile, String code)
throws ServiceException;
CommonResult<OAuth2AccessTokenBO> getAccessToken2(String mobile, String code);
CommonResult<OAuth2AccessTokenBO> getAccessToken(String mobile, String code);
/**
* 校验访问令牌,获取身份信息( 不包括 accessToken 等等 )

View File

@@ -47,31 +47,7 @@ public class MobileCodeServiceImpl implements MobileCodeService {
* @param code 验证码
* @return 手机验证码信息
*/
public MobileCodeDO validLastMobileCode(String mobile, String code) {
MobileCodeDO mobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
if (mobileCodePO == null) { // 若验证码不存在,抛出异常
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_NOT_FOUND.getCode());
}
if (System.currentTimeMillis() - mobileCodePO.getCreateTime().getTime() >= codeExpireTimes) { // 验证码已过期
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_EXPIRED.getCode());
}
if (mobileCodePO.getUsed()) { // 验证码已使用
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_USED.getCode());
}
if (!mobileCodePO.getCode().equals(code)) {
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_NOT_CORRECT.getCode());
}
return mobileCodePO;
}
/**
* 校验手机号的最后一个手机验证码是否有效
*
* @param mobile 手机号
* @param code 验证码
* @return 手机验证码信息
*/
public CommonResult<MobileCodeDO> validLastMobileCode2(String mobile, String code) {
public CommonResult<MobileCodeDO> validLastMobileCode(String mobile, String code) {
MobileCodeDO mobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
if (mobileCodePO == null) { // 若验证码不存在,抛出异常
return ServiceExceptionUtil.error(UserErrorCodeEnum.MOBILE_CODE_NOT_FOUND.getCode());

View File

@@ -52,29 +52,9 @@ public class OAuth2ServiceImpl implements OAuth2Service {
@Override
@Transactional
public OAuth2AccessTokenBO getAccessToken(String mobile, String code) {
// 校验手机号的最后一个手机验证码是否有效
MobileCodeDO mobileCodeDO = mobileCodeService.validLastMobileCode(mobile, code);
// 获取用户
UserDO userDO = userService.getUser(mobile);
if (userDO == null) { // 用户不存在
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.USER_MOBILE_NOT_REGISTERED.getCode());
}
// 创建刷新令牌
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userDO.getId());
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userDO.getId(), oauth2RefreshTokenDO.getId());
// 标记已使用
mobileCodeService.useMobileCode(mobileCodeDO.getId(), userDO.getId());
// 转换返回
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
}
@Override
@Transactional
public CommonResult<OAuth2AccessTokenBO> getAccessToken2(String mobile, String code) {
public CommonResult<OAuth2AccessTokenBO> getAccessToken(String mobile, String code) {
// 校验传入的 mobile 和 code 是否合法
CommonResult<MobileCodeDO> result = mobileCodeService.validLastMobileCode2(mobile, code);
CommonResult<MobileCodeDO> result = mobileCodeService.validLastMobileCode(mobile, code);
if (result.isError()) {
return CommonResult.error(result);
}

View File

@@ -4,17 +4,17 @@
<insert id="insert" parameterType="OAuth2AccessTokenDO">
INSERT INTO oauth2_access_token (
id, refresh_token, uid, valid, expires_time,
id, refresh_token, adminId, valid, expires_time,
create_time
) VALUES (
#{id}, #{refreshToken}, #{uid}, #{valid}, #{expiresTime},
#{id}, #{refreshToken}, #{adminId}, #{valid}, #{expiresTime},
#{createTime}
)
</insert>
<select id="selectByTokenId" parameterType="String" resultType="OAuth2AccessTokenDO">
SELECT
id, uid, valid, expires_time
id, adminId, valid, expires_time
FROM oauth2_access_token
WHERE id = #{id}
</select>

View File

@@ -4,9 +4,9 @@
<insert id="insert" parameterType="OAuth2RefreshTokenDO">
INSERT INTO oauth2_refresh_token (
id, uid, valid, expires_time, create_time
id, adminId, valid, expires_time, create_time
) VALUES (
#{id}, #{uid}, #{valid}, #{expiresTime}, #{createTime}
#{id}, #{adminId}, #{valid}, #{expiresTime}, #{createTime}
)
</insert>