mirror of
https://github.com/201206030/novel.git
synced 2025-04-27 07:30:50 +00:00
refactor: 策略模式重构用户认证授权功能
This commit is contained in:
parent
cdd1455ab9
commit
d2e7590646
@ -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 校验
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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<AuthorInfo> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -77,6 +77,11 @@ public enum ErrorCodeEnum {
|
|||||||
* */
|
* */
|
||||||
USER_LOGIN_EXPIRED("A0230","用户登录已过期"),
|
USER_LOGIN_EXPIRED("A0230","用户登录已过期"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问未授权
|
||||||
|
* */
|
||||||
|
USER_UN_AUTH("A0301","访问未授权"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一级宏观错误码,系统执行出错
|
* 一级宏观错误码,系统执行出错
|
||||||
* */
|
* */
|
||||||
|
@ -32,7 +32,8 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
, ApiRouterConsts.API_ADMIN_URL_PREFIX + "/**")
|
, ApiRouterConsts.API_ADMIN_URL_PREFIX + "/**")
|
||||||
// 放行登录注册相关请求接口
|
// 放行登录注册相关请求接口
|
||||||
.excludePathPatterns(ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/register"
|
.excludePathPatterns(ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/register"
|
||||||
, ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/login",
|
, ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/login"
|
||||||
ApiRouterConsts.API_ADMIN_URL_PREFIX + "/login");
|
, ApiRouterConsts.API_AUTHOR_URL_PREFIX + "/register"
|
||||||
|
,ApiRouterConsts.API_ADMIN_URL_PREFIX + "/login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小说类别表
|
* 小说类别表
|
||||||
*/
|
*/
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package io.github.xxyopen.novel.core.intercepter;
|
package io.github.xxyopen.novel.core.intercepter;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
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.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.common.resp.RestResp;
|
||||||
import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
|
import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
|
||||||
import io.github.xxyopen.novel.core.constant.SystemConfigConsts;
|
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.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -14,7 +15,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Objects;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证 拦截器
|
* 认证 拦截器
|
||||||
@ -27,34 +28,36 @@ import java.util.Objects;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AuthInterceptor implements HandlerInterceptor {
|
public class AuthInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
private final JwtUtils jwtUtils;
|
private final Map<String,AuthStrategy> authStrategy;
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
@SuppressWarnings("NullableProblems")
|
@SuppressWarnings("NullableProblems")
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
// 校验登录JWT
|
// 获取登录 JWT
|
||||||
String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME);
|
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);
|
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||||
response.getWriter().write(objectMapper.writeValueAsString(RestResp.fail(ErrorCodeEnum.USER_LOGIN_EXPIRED)));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user