add
This commit is contained in:
@ -91,6 +91,7 @@ qiaoba:
|
|||||||
- /druid/**
|
- /druid/**
|
||||||
- /resource/**
|
- /resource/**
|
||||||
- /login
|
- /login
|
||||||
|
- /getInfo
|
||||||
- /register
|
- /register
|
||||||
- /captchaImage
|
- /captchaImage
|
||||||
- /tenant/normal-list
|
- /tenant/normal-list
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.qiaoba.auth.config;
|
package com.qiaoba.auth.config;
|
||||||
|
|
||||||
import com.qiaoba.api.auth.constants.SecurityConstant;
|
import com.qiaoba.api.auth.constants.SecurityConstant;
|
||||||
import com.qiaoba.auth.filters.AuthenticationCoreFilter;
|
import com.qiaoba.auth.filters.SecurityContextHolderFilter;
|
||||||
import com.qiaoba.auth.handler.AccessDeniedHandler;
|
import com.qiaoba.auth.handler.AccessDeniedHandler;
|
||||||
import com.qiaoba.auth.handler.LogoutHandler;
|
import com.qiaoba.auth.handler.LogoutHandler;
|
||||||
import com.qiaoba.auth.properties.AuthConfigProperties;
|
import com.qiaoba.auth.properties.AuthConfigProperties;
|
||||||
@ -36,7 +36,7 @@ public class SpringSecurityConfig {
|
|||||||
|
|
||||||
private final AuthConfigProperties authConfigProperties;
|
private final AuthConfigProperties authConfigProperties;
|
||||||
private final AccessDeniedHandler accessDeniedHandler;
|
private final AccessDeniedHandler accessDeniedHandler;
|
||||||
private final AuthenticationCoreFilter authenticationCoreFilter;
|
private final SecurityContextHolderFilter securityContextHolderFilter;
|
||||||
private final LogoutHandler logoutHandler;
|
private final LogoutHandler logoutHandler;
|
||||||
|
|
||||||
|
|
||||||
@ -72,8 +72,8 @@ public class SpringSecurityConfig {
|
|||||||
// 退出处理
|
// 退出处理
|
||||||
httpSecurity.logout().logoutUrl(SecurityConstant.LOGOUT_URI).logoutSuccessHandler(logoutHandler);
|
httpSecurity.logout().logoutUrl(SecurityConstant.LOGOUT_URI).logoutSuccessHandler(logoutHandler);
|
||||||
// 添加JWT filter
|
// 添加JWT filter
|
||||||
httpSecurity.addFilterBefore(authenticationCoreFilter, UsernamePasswordAuthenticationFilter.class);
|
httpSecurity.addFilterBefore(securityContextHolderFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
httpSecurity.addFilterBefore(authenticationCoreFilter, LogoutFilter.class);
|
httpSecurity.addFilterBefore(securityContextHolderFilter, LogoutFilter.class);
|
||||||
return httpSecurity.build();
|
return httpSecurity.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
package com.qiaoba.auth.filters;
|
package com.qiaoba.auth.filters;
|
||||||
|
|
||||||
import com.qiaoba.api.auth.service.AuthConfigApiService;
|
|
||||||
import com.qiaoba.api.auth.constants.SecurityConstant;
|
import com.qiaoba.api.auth.constants.SecurityConstant;
|
||||||
import com.qiaoba.api.auth.entity.dto.OnlineUserDto;
|
import com.qiaoba.api.auth.entity.dto.OnlineUserDto;
|
||||||
import com.qiaoba.auth.properties.AuthConfigProperties;
|
import com.qiaoba.api.auth.service.AuthConfigApiService;
|
||||||
import com.qiaoba.api.auth.service.OnlineUserService;
|
import com.qiaoba.api.auth.service.OnlineUserService;
|
||||||
import com.qiaoba.api.auth.utils.TokenUtil;
|
import com.qiaoba.api.auth.utils.TokenUtil;
|
||||||
|
import com.qiaoba.auth.properties.AuthConfigProperties;
|
||||||
|
import com.qiaoba.common.base.order.FilterOrder;
|
||||||
import com.qiaoba.common.redis.service.RedisService;
|
import com.qiaoba.common.redis.service.RedisService;
|
||||||
import com.qiaoba.common.web.utils.ResponseUtil;
|
import com.qiaoba.common.web.utils.ResponseUtil;
|
||||||
import com.qiaoba.common.web.utils.UriUtil;
|
import com.qiaoba.common.web.utils.UriUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
@ -26,28 +25,26 @@ import java.io.IOException;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 鉴权核心过滤器
|
* 在线用户过滤器
|
||||||
*
|
*
|
||||||
* @author ailanyin
|
* @author ailanyin
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 2023-05-28 15:31:55
|
* @since 2023/7/6 9:14
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AuthenticationCoreFilter extends OncePerRequestFilter {
|
@Order(FilterOrder.ONLINE_USER_FILTER_ORDER)
|
||||||
|
public class OnlineUserFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private final RedisService redisService;
|
|
||||||
private final UserDetailsService userDetailsService;
|
|
||||||
private final OnlineUserService onlineUserService;
|
|
||||||
private final AuthConfigProperties authConfigProperties;
|
private final AuthConfigProperties authConfigProperties;
|
||||||
private final AuthConfigApiService authConfigApiService;
|
private final AuthConfigApiService authConfigApiService;
|
||||||
|
private final RedisService redisService;
|
||||||
|
private final OnlineUserService onlineUserService;
|
||||||
|
private final UserDetailsService userDetailsService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request,
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||||
HttpServletResponse response,
|
log.debug("Start run OnlineUserFilter, Uri: {}", request.getRequestURI());
|
||||||
FilterChain chain) throws ServletException, IOException {
|
|
||||||
log.debug("Start run AuthenticationCoreFilter, Uri: {}", request.getRequestURI());
|
|
||||||
// 白名单 放行
|
// 白名单 放行
|
||||||
for (String uri : authConfigProperties.getWhitelist()) {
|
for (String uri : authConfigProperties.getWhitelist()) {
|
||||||
if (UriUtil.match(uri, request.getRequestURI())) {
|
if (UriUtil.match(uri, request.getRequestURI())) {
|
||||||
@ -84,13 +81,6 @@ public class AuthenticationCoreFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新 SecurityContextHolder Authentication, 为了保证 SecurityContext 上下文中 userDetails 是最新的
|
|
||||||
if (Objects.nonNull(userDetails) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
|
|
||||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
|
||||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.qiaoba.auth.filters;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.qiaoba.api.auth.utils.TokenUtil;
|
||||||
|
import com.qiaoba.auth.properties.AuthConfigProperties;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 鉴权核心过滤器
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023-05-28 15:31:55
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class SecurityContextHolderFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
|
||||||
|
private final UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain chain) throws ServletException, IOException {
|
||||||
|
log.debug("Start run SecurityContextHolderFilter, Uri: {}", request.getRequestURI());
|
||||||
|
|
||||||
|
String username = TokenUtil.analyzeUsername(request);
|
||||||
|
if (StrUtil.isNotBlank(username)) {
|
||||||
|
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||||
|
// 更新 SecurityContextHolder Authentication, 为了保证 SecurityContext 上下文中 userDetails 是最新的
|
||||||
|
if (Objects.nonNull(userDetails) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
|
||||||
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
||||||
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.qiaoba.auth.handler;
|
package com.qiaoba.auth.handler;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.qiaoba.api.auth.entity.LoginUser;
|
import com.qiaoba.api.auth.entity.LoginUser;
|
||||||
import com.qiaoba.api.auth.service.OnlineUserService;
|
import com.qiaoba.api.auth.service.OnlineUserService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -28,7 +29,9 @@ public class LogoutHandler implements LogoutSuccessHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||||
// 删除缓存中的用户信息
|
// 删除缓存中的用户信息
|
||||||
LoginUser user = (LoginUser) authentication.getPrincipal();
|
if (ObjectUtil.isNotEmpty(authentication) && ObjectUtil.isNotEmpty(authentication.getPrincipal())) {
|
||||||
onlineUserService.deleteOne(user.getUsername(), user.getDeviceSn(), true);
|
LoginUser user = (LoginUser) authentication.getPrincipal();
|
||||||
|
onlineUserService.deleteOne(user.getUsername(), user.getDeviceSn(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|||||||
com.qiaoba.auth.properties.AuthConfigProperties,\
|
com.qiaoba.auth.properties.AuthConfigProperties,\
|
||||||
com.qiaoba.auth.handler.AccessDeniedHandler,\
|
com.qiaoba.auth.handler.AccessDeniedHandler,\
|
||||||
com.qiaoba.auth.handler.LogoutHandler,\
|
com.qiaoba.auth.handler.LogoutHandler,\
|
||||||
com.qiaoba.auth.filters.AuthenticationCoreFilter,\
|
com.qiaoba.auth.filters.OnlineUserFilter,\
|
||||||
|
com.qiaoba.auth.filters.SecurityContextHolderFilter,\
|
||||||
com.qiaoba.auth.advice.SecurityExceptionAdvice,\
|
com.qiaoba.auth.advice.SecurityExceptionAdvice,\
|
||||||
com.qiaoba.auth.aspectj.DataScopeAspect,\
|
com.qiaoba.auth.aspectj.DataScopeAspect,\
|
||||||
com.qiaoba.auth.service.impl.OnlineUserServiceImpl,\
|
com.qiaoba.auth.service.impl.OnlineUserServiceImpl,\
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.qiaoba.common.base.order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤器执行顺序
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023/7/6 9:22
|
||||||
|
*/
|
||||||
|
public interface FilterOrder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态数据源过滤器-执行顺序(最高)
|
||||||
|
*/
|
||||||
|
int DYNAMIC_DATASOURCE_FILTER_ORDER = -10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线用户过滤器
|
||||||
|
*/
|
||||||
|
int ONLINE_USER_FILTER_ORDER = -9999;
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.qiaoba.common.web.utils;
|
|||||||
|
|
||||||
import cn.hutool.http.ContentType;
|
import cn.hutool.http.ContentType;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.qiaoba.common.base.constants.BaseConstant;
|
||||||
import com.qiaoba.common.base.result.AjaxResult;
|
import com.qiaoba.common.base.result.AjaxResult;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@ -20,7 +21,7 @@ public class ResponseUtil {
|
|||||||
public static void response(HttpServletResponse response, String msg) throws IOException {
|
public static void response(HttpServletResponse response, String msg) throws IOException {
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
response.setContentType(ContentType.JSON.getValue());
|
response.setContentType(ContentType.JSON.getValue());
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding(BaseConstant.UTF8);
|
||||||
PrintWriter writer = response.getWriter();
|
PrintWriter writer = response.getWriter();
|
||||||
writer.write(msg);
|
writer.write(msg);
|
||||||
writer.close();
|
writer.close();
|
||||||
|
@ -9,6 +9,7 @@ import com.qiaoba.common.base.code.TenantErrorCode;
|
|||||||
import com.qiaoba.common.base.constants.BaseConstant;
|
import com.qiaoba.common.base.constants.BaseConstant;
|
||||||
import com.qiaoba.common.base.constants.TenantConstant;
|
import com.qiaoba.common.base.constants.TenantConstant;
|
||||||
import com.qiaoba.common.base.context.BaseContext;
|
import com.qiaoba.common.base.context.BaseContext;
|
||||||
|
import com.qiaoba.common.base.order.FilterOrder;
|
||||||
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
|
||||||
import com.qiaoba.common.web.utils.ResponseUtil;
|
import com.qiaoba.common.web.utils.ResponseUtil;
|
||||||
import com.qiaoba.common.web.utils.UriUtil;
|
import com.qiaoba.common.web.utils.UriUtil;
|
||||||
@ -36,7 +37,7 @@ import java.util.Objects;
|
|||||||
* @since 2023-04-25 22:48:43
|
* @since 2023-04-25 22:48:43
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Order(-10000)
|
@Order(FilterOrder.DYNAMIC_DATASOURCE_FILTER_ORDER)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
public class DynamicDataSourceFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user