diff --git a/src/main/java/io/github/xxyopen/novel/core/auth/AdminAuthStrategy.java b/src/main/java/io/github/xxyopen/novel/core/auth/AdminAuthStrategy.java new file mode 100644 index 0000000..dd8d093 --- /dev/null +++ b/src/main/java/io/github/xxyopen/novel/core/auth/AdminAuthStrategy.java @@ -0,0 +1,27 @@ +package io.github.xxyopen.novel.core.auth; + +import io.github.xxyopen.novel.core.common.exception.BusinessException; +import io.github.xxyopen.novel.core.util.JwtUtils; +import io.github.xxyopen.novel.dao.mapper.UserInfoMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 平台后台管理系统 认证策略 + * + * @author xiongxiaoyang + * @date 2022/5/18 + */ +@Component +@RequiredArgsConstructor +public class AdminAuthStrategy implements AuthStrategy { + + private final JwtUtils jwtUtils; + + private final UserInfoMapper userInfoMapper; + + @Override + public void auth(String token) throws BusinessException { + // TODO 平台后台 token 校验 + } +} \ No newline at end of file diff --git a/src/main/java/io/github/xxyopen/novel/core/auth/AuthStrategy.java b/src/main/java/io/github/xxyopen/novel/core/auth/AuthStrategy.java new file mode 100644 index 0000000..e366284 --- /dev/null +++ b/src/main/java/io/github/xxyopen/novel/core/auth/AuthStrategy.java @@ -0,0 +1,53 @@ +package io.github.xxyopen.novel.core.auth; + +import io.github.xxyopen.novel.core.common.constant.ErrorCodeEnum; +import io.github.xxyopen.novel.core.common.exception.BusinessException; +import io.github.xxyopen.novel.core.constant.SystemConfigConsts; +import io.github.xxyopen.novel.core.util.JwtUtils; +import io.github.xxyopen.novel.dao.entity.UserInfo; +import io.github.xxyopen.novel.dao.mapper.UserInfoMapper; + +import java.util.Objects; + +/** + * 策略模式实现用户认证授权功能 + * + * @author xiongxiaoyang + * @date 2022/5/18 + */ +public interface AuthStrategy { + + /** + * 请求用户认证 + * + * @param token 登录 token + * @throws BusinessException 认证失败则抛出义务异常 + */ + void auth(String token) throws BusinessException; + + /** + * 前台多系统单点登录统一账号认证(门户系统、作家系统以及后面会扩展的漫画系统和视频系统等) + * + * @param jwtUtils jwt 工具 + * @param userInfoMapper 用户查询 Mapper + * @param token token 登录 token + * @return 用户ID + */ + default Long authSSO(JwtUtils jwtUtils, UserInfoMapper userInfoMapper, String token) { + if (Objects.isNull(token)) { + // token 为空 + throw new BusinessException(ErrorCodeEnum.USER_LOGIN_EXPIRED); + } + Long userId = jwtUtils.parseToken(token, SystemConfigConsts.NOVEL_FRONT_KEY); + if (Objects.isNull(userId)) { + // token 解析失败 + throw new BusinessException(ErrorCodeEnum.USER_LOGIN_EXPIRED); + } + UserInfo userInfo = userInfoMapper.selectById(userId); + if (Objects.isNull(userInfo)) { + // 用户不存在 + throw new BusinessException(ErrorCodeEnum.USER_ACCOUNT_NOT_EXIST); + } + return userId; + } +} diff --git a/src/main/java/io/github/xxyopen/novel/core/auth/AuthorAuthStrategy.java b/src/main/java/io/github/xxyopen/novel/core/auth/AuthorAuthStrategy.java new file mode 100644 index 0000000..046b50a --- /dev/null +++ b/src/main/java/io/github/xxyopen/novel/core/auth/AuthorAuthStrategy.java @@ -0,0 +1,48 @@ +package io.github.xxyopen.novel.core.auth; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.github.xxyopen.novel.core.common.constant.ErrorCodeEnum; +import io.github.xxyopen.novel.core.common.exception.BusinessException; +import io.github.xxyopen.novel.core.constant.DatabaseConsts; +import io.github.xxyopen.novel.core.util.JwtUtils; +import io.github.xxyopen.novel.dao.entity.AuthorInfo; +import io.github.xxyopen.novel.dao.mapper.AuthorInfoMapper; +import io.github.xxyopen.novel.dao.mapper.UserInfoMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +/** + * 作家后台管理系统 认证策略 + * + * @author xiongxiaoyang + * @date 2022/5/18 + */ +@Component +@RequiredArgsConstructor +public class AuthorAuthStrategy implements AuthStrategy { + + private final JwtUtils jwtUtils; + + private final UserInfoMapper userInfoMapper; + + private final AuthorInfoMapper authorInfoMapper; + + @Override + public void auth(String token) throws BusinessException { + // 统一账号认证 + Long userId = authSSO(jwtUtils, userInfoMapper, token); + + // 作家权限认证 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper + .eq(DatabaseConsts.AuthorInfoTable.ColumnEnum.USER_ID.getName(), userId) + .last(DatabaseConsts.SqlEnum.LIMIT_1.getSql()); + AuthorInfo authorInfo = authorInfoMapper.selectOne(queryWrapper); + if(Objects.isNull(authorInfo)){ + // 作家账号不存在,无权访问作家专区 + throw new BusinessException(ErrorCodeEnum.USER_UN_AUTH); + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/xxyopen/novel/core/auth/FrontAuthStrategy.java b/src/main/java/io/github/xxyopen/novel/core/auth/FrontAuthStrategy.java new file mode 100644 index 0000000..ef7f90c --- /dev/null +++ b/src/main/java/io/github/xxyopen/novel/core/auth/FrontAuthStrategy.java @@ -0,0 +1,28 @@ +package io.github.xxyopen.novel.core.auth; + +import io.github.xxyopen.novel.core.common.exception.BusinessException; +import io.github.xxyopen.novel.core.util.JwtUtils; +import io.github.xxyopen.novel.dao.mapper.UserInfoMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 前台门户系统 认证策略 + * + * @author xiongxiaoyang + * @date 2022/5/18 + */ +@Component +@RequiredArgsConstructor +public class FrontAuthStrategy implements AuthStrategy { + + private final JwtUtils jwtUtils; + + private final UserInfoMapper userInfoMapper; + + @Override + public void auth(String token) throws BusinessException { + // 统一账号认证 + authSSO(jwtUtils,userInfoMapper,token); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/xxyopen/novel/core/common/constant/ErrorCodeEnum.java b/src/main/java/io/github/xxyopen/novel/core/common/constant/ErrorCodeEnum.java index ab1e609..7a36de8 100644 --- a/src/main/java/io/github/xxyopen/novel/core/common/constant/ErrorCodeEnum.java +++ b/src/main/java/io/github/xxyopen/novel/core/common/constant/ErrorCodeEnum.java @@ -77,6 +77,11 @@ public enum ErrorCodeEnum { * */ USER_LOGIN_EXPIRED("A0230","用户登录已过期"), + /** + * 访问未授权 + * */ + USER_UN_AUTH("A0301","访问未授权"), + /** * 一级宏观错误码,系统执行出错 * */ diff --git a/src/main/java/io/github/xxyopen/novel/core/config/WebConfig.java b/src/main/java/io/github/xxyopen/novel/core/config/WebConfig.java index 9b82ef6..96bc548 100644 --- a/src/main/java/io/github/xxyopen/novel/core/config/WebConfig.java +++ b/src/main/java/io/github/xxyopen/novel/core/config/WebConfig.java @@ -32,7 +32,8 @@ public class WebConfig implements WebMvcConfigurer { , ApiRouterConsts.API_ADMIN_URL_PREFIX + "/**") // 放行登录注册相关请求接口 .excludePathPatterns(ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/register" - , ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/login", - ApiRouterConsts.API_ADMIN_URL_PREFIX + "/login"); + , ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/login" + , ApiRouterConsts.API_AUTHOR_URL_PREFIX + "/register" + ,ApiRouterConsts.API_ADMIN_URL_PREFIX + "/login"); } } diff --git a/src/main/java/io/github/xxyopen/novel/core/constant/DatabaseConsts.java b/src/main/java/io/github/xxyopen/novel/core/constant/DatabaseConsts.java index 0fca87f..34875e5 100644 --- a/src/main/java/io/github/xxyopen/novel/core/constant/DatabaseConsts.java +++ b/src/main/java/io/github/xxyopen/novel/core/constant/DatabaseConsts.java @@ -31,6 +31,26 @@ public class DatabaseConsts { } + /** + * 作家信息表 + */ + public static class AuthorInfoTable { + + @Getter + public enum ColumnEnum { + + USER_ID("user_id"); + + private String name; + + ColumnEnum(String name) { + this.name = name; + } + + } + + } + /** * 小说类别表 */ diff --git a/src/main/java/io/github/xxyopen/novel/core/intercepter/AuthInterceptor.java b/src/main/java/io/github/xxyopen/novel/core/intercepter/AuthInterceptor.java index 22d88f7..9b38de4 100644 --- a/src/main/java/io/github/xxyopen/novel/core/intercepter/AuthInterceptor.java +++ b/src/main/java/io/github/xxyopen/novel/core/intercepter/AuthInterceptor.java @@ -1,11 +1,12 @@ package io.github.xxyopen.novel.core.intercepter; import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.xxyopen.novel.core.auth.AuthStrategy; import io.github.xxyopen.novel.core.common.constant.ErrorCodeEnum; +import io.github.xxyopen.novel.core.common.exception.BusinessException; import io.github.xxyopen.novel.core.common.resp.RestResp; import io.github.xxyopen.novel.core.constant.ApiRouterConsts; import io.github.xxyopen.novel.core.constant.SystemConfigConsts; -import io.github.xxyopen.novel.core.util.JwtUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; @@ -14,7 +15,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import java.nio.charset.StandardCharsets; -import java.util.Objects; +import java.util.Map; /** * 认证 拦截器 @@ -27,34 +28,36 @@ import java.util.Objects; @RequiredArgsConstructor public class AuthInterceptor implements HandlerInterceptor { - private final JwtUtils jwtUtils; + private final Map authStrategy; private final ObjectMapper objectMapper; @SuppressWarnings("NullableProblems") @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - // 校验登录JWT + // 获取登录 JWT String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME); - if (!Objects.isNull(token)) { - String requestUri = request.getRequestURI(); - if (requestUri.contains(ApiRouterConsts.API_FRONT_USER_URL_PREFIX) - || requestUri.contains(ApiRouterConsts.API_AUTHOR_URL_PREFIX)) { - // 校验会员和作家的登录权限 - Long userId = jwtUtils.parseToken(token, SystemConfigConsts.NOVEL_FRONT_KEY); - if (!Objects.isNull(userId)) { - // TODO 查询用户信息并校验账号状态是否正常 - // 认证成功 - return HandlerInterceptor.super.preHandle(request, response, handler); - } - }else{ - // TODO 校验后台的登录权限 - } + // 获取请求的 URI + String requestUri = request.getRequestURI(); + + // 根据请求的 URI 得到认证策略 + String authStrategyName = requestUri.substring(ApiRouterConsts.API_URL_PREFIX.length() + 1); + authStrategyName = authStrategyName.substring(0,authStrategyName.indexOf("/")); + authStrategyName = String.format("%sAuthStrategy",authStrategyName); + + // 开始认证 + try { + authStrategy.get(authStrategyName).auth(token); + }catch (BusinessException exception){ + // 认证失败 + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.getWriter().write(objectMapper.writeValueAsString(RestResp.fail(ErrorCodeEnum.USER_LOGIN_EXPIRED))); + return false; } - response.setCharacterEncoding(StandardCharsets.UTF_8.name()); - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - response.getWriter().write(objectMapper.writeValueAsString(RestResp.fail(ErrorCodeEnum.USER_LOGIN_EXPIRED))); - return false; + // 认证成功 + return HandlerInterceptor.super.preHandle(request, response, handler); + } }