diff --git a/admin-api/java-api/pom.xml b/admin-api/java-api/pom.xml index a49a58fb..b22ecf4d 100644 --- a/admin-api/java-api/pom.xml +++ b/admin-api/java-api/pom.xml @@ -33,6 +33,11 @@ + + cn.dev33 + sa-token-spring-boot-starter + 1.27.0 + org.springframework.boot @@ -67,12 +72,6 @@ - - - org.springframework.boot - spring-boot-starter-security - - org.springframework.boot spring-boot-starter-log4j2 diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/satoken/SaTokenAuthAction.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/satoken/SaTokenAuthAction.java new file mode 100644 index 00000000..9939d83b --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/satoken/SaTokenAuthAction.java @@ -0,0 +1,54 @@ +package net.lab1024.smartadmin.service.common.satoken; + +import cn.dev33.satoken.action.SaTokenActionDefaultImpl; +import cn.dev33.satoken.stp.StpUtil; +import net.lab1024.smartadmin.service.common.annoation.NoNeedLogin; +import net.lab1024.smartadmin.service.common.annoation.NoValidPrivilege; +import net.lab1024.smartadmin.service.common.util.SmartStringUtil; +import net.lab1024.smartadmin.service.module.system.menu.service.MenuEmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.List; + +/** + * [ sa-token 为支持SmartAdmin 设置所有方法默认存在权限,权限key为类目+方法名 ] + * + * @author yandanyang + * @date 2021/10/13 17:48 + */ +@Component +public class SaTokenAuthAction extends SaTokenActionDefaultImpl { + + @Autowired + private MenuEmployeeService menuEmployeeService; + + @Override + public void validateAnnotation(AnnotatedElement target) { + super.validateAnnotation(target); + if (target instanceof Method) { + Method method = (Method) target; + NoNeedLogin noNeedLogin = method.getAnnotation(NoNeedLogin.class); + if (noNeedLogin != null) { + return; + } + NoValidPrivilege noValidPrivilege = method.getAnnotation(NoValidPrivilege.class); + if (noValidPrivilege != null) { + return; + } + Long employeeId = StpUtil.getLoginIdAsLong(); + Boolean isSuperman = menuEmployeeService.isSuperman(employeeId); + if(isSuperman){ + return; + } + String className = method.getDeclaringClass().getName(); + String methodName = method.getName(); + List list = SmartStringUtil.splitConvertToList(className, "\\."); + String controllerName = list.get(list.size() - 1); + String permissionName = controllerName + "." + methodName; + StpUtil.stpLogic.checkPermission(permissionName); + } + } +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/satoken/SaTokenAuthStp.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/satoken/SaTokenAuthStp.java new file mode 100644 index 00000000..e76d7ae9 --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/satoken/SaTokenAuthStp.java @@ -0,0 +1,53 @@ +package net.lab1024.smartadmin.service.common.satoken; + +import cn.dev33.satoken.stp.StpInterface; +import com.google.common.collect.Lists; +import net.lab1024.smartadmin.service.module.system.employee.service.EmployeeService; +import net.lab1024.smartadmin.service.module.system.login.domain.RequestEmployee; +import net.lab1024.smartadmin.service.module.system.menu.domain.vo.MenuVO; +import net.lab1024.smartadmin.service.module.system.menu.service.MenuEmployeeService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * [ 获取某一用户对于的权限列表以及角色信息 ] + * + * @author yandanyang + * @date 2021/10/13 16:56 + */ +@Component +public class SaTokenAuthStp implements StpInterface { + + @Autowired + private EmployeeService employeeService; + @Autowired + private MenuEmployeeService menuEmployeeService; + + + @Override + public List getPermissionList(Object loginId, String loginType) { + List permissionList = Lists.newArrayList(); + + RequestEmployee requestEmployee = employeeService.getById(NumberUtils.toLong(loginId.toString())); + List menuList = menuEmployeeService.getMenuByRoleIdList(requestEmployee.getRoleList(), requestEmployee.getIsSuperMan()); + menuList.forEach(e -> { + if(CollectionUtils.isNotEmpty(e.getPermsList())){ + permissionList.addAll(e.getPermsList()); + } + }); + return permissionList; + } + + @Override + public List getRoleList(Object loginId, String loginType) { + RequestEmployee loginInfoDTO = employeeService.getById(NumberUtils.toLong(loginId.toString())); + List roleIdList = loginInfoDTO.getRoleList(); + List roleList = roleIdList.stream().map(e -> e.toString()).collect(Collectors.toList()); + return roleList; + } +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityAuthenticationFailHandler.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityAuthenticationFailHandler.java deleted file mode 100644 index f777a388..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityAuthenticationFailHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.lab1024.smartadmin.service.common.security; - -import com.alibaba.fastjson.JSONObject; -import net.lab1024.smartadmin.service.common.code.ErrorCode; -import net.lab1024.smartadmin.service.common.code.UserErrorCode; -import net.lab1024.smartadmin.service.common.domain.ResponseDTO; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * - * [ 认证失败处理 ] - * - * @author - * @date - */ -public class SecurityAuthenticationFailHandler implements AuthenticationEntryPoint { - - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { - this.outputResult(response, UserErrorCode.LOGIN_STATE_INVALID); - } - - /** - * 输出 - * - * @param response - * @param errorCode - * @throws IOException - */ - private void outputResult(HttpServletResponse response, ErrorCode errorCode) throws IOException { - String msg = JSONObject.toJSONString(ResponseDTO.error(errorCode)); - response.setContentType("application/json;charset=UTF-8"); - response.getWriter().write(msg); - response.flushBuffer(); - } -} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityMetadataSource.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityMetadataSource.java deleted file mode 100644 index 8173ddd1..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityMetadataSource.java +++ /dev/null @@ -1,114 +0,0 @@ -package net.lab1024.smartadmin.service.common.security; - -import net.lab1024.smartadmin.service.common.annoation.NoValidPrivilege; -import org.apache.commons.lang3.StringUtils; -import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.access.prepost.*; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.CollectionUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import java.lang.reflect.Method; -import java.util.*; - -/** - * 此类用于默认给所有接口添加权限 @privilegeCheck.checkPermission('%s') - * %s 为类名.方法名 - * 和使用@PreAuthorize("@privilegeCheck.checkPermission('%s')") 效果一致 - * 避免所有接口都添加一遍 减轻工作量 - * - * @author 罗伊 - * @date 2021-08-30 23:08 - */ -public class SecurityMetadataSource extends PrePostAnnotationSecurityMetadataSource { - - public static final String PRIVILEGE_CHECK_NAME = "privilegeCheck"; - - private static String EXPRESSION_FORMAT = "@privilegeCheck.checkPermission('%s')"; - - private final PrePostInvocationAttributeFactory attributeFactory; - - private SecurityUrlMatchers securityUrlMatchers; - - public SecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory, SecurityUrlMatchers securityUrlMatchers) { - super(attributeFactory); - this.attributeFactory = attributeFactory; - this.securityUrlMatchers = securityUrlMatchers; - } - - - @Override - public Collection getAttributes(Method method, Class targetClass) { - - //只对固定的包的所有接口进行控制 - if (!targetClass.getName().startsWith(securityUrlMatchers.getValidPackage())) { - return super.getAttributes(method, targetClass); - } - //自己的控制 - GetMapping getMapping = method.getAnnotation(GetMapping.class); - PostMapping postMapping = method.getAnnotation(PostMapping.class); - RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); - if (getMapping == null && postMapping == null && requestMapping == null) { - return super.getAttributes(method, targetClass); - } - - //是否需要权限 - NoValidPrivilege methodNoValidPrivilege = method.getAnnotation(NoValidPrivilege.class); - if (methodNoValidPrivilege != null) { - return Collections.emptyList(); - } - NoValidPrivilege classNoValidPrivilege = targetClass.getAnnotation(NoValidPrivilege.class); - if (classNoValidPrivilege != null) { - return Collections.emptyList(); - } - //是否添加security原有注解 - PreAuthorize preAuthorize = method.getAnnotation(PreAuthorize.class); - if (preAuthorize != null) { - return super.getAttributes(method, targetClass); - } - PostAuthorize postAuthorize = method.getAnnotation(PostAuthorize.class); - if (postAuthorize != null) { - return super.getAttributes(method, targetClass); - } - //URL匹配 - AntPathMatcher antPathMatcher = new AntPathMatcher(); - antPathMatcher.setCaseSensitive(false); - antPathMatcher.setTrimTokens(true); - //无需验证的URL集合 - List noValidUrlList = securityUrlMatchers.getNoValidUrl(); - //获取方法的请求路径 - Set methodUrl = securityUrlMatchers.getMethodUrl(method); - if (this.contain(antPathMatcher, noValidUrlList, methodUrl)) { - return super.getAttributes(method, targetClass); - } - ArrayList configAttributes = new ArrayList(1); - String classFullName = targetClass.getName(); - String methodName = method.getName(); - String[] classNameArray = StringUtils.split(classFullName, "\\."); - String controllerName = classNameArray[classNameArray.length - 1]; - String privilegeName = controllerName + "." + methodName; - String preAuthorizeAttribute = String.format(EXPRESSION_FORMAT, privilegeName); - PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(null, null, preAuthorizeAttribute); - if (pre != null) { - configAttributes.add(pre); - } - return configAttributes; - } - - public Boolean contain(AntPathMatcher antPathMatcher, List ignores, Set urls) { - if (CollectionUtils.isEmpty(ignores)) { - return false; - } - for (String ignoreUrl : ignores) { - for (String url : urls) { - if (antPathMatcher.match(ignoreUrl, url)) { - return true; - } - } - } - return false; - } - -} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityUrlMatchers.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityUrlMatchers.java deleted file mode 100644 index 21025187..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/security/SecurityUrlMatchers.java +++ /dev/null @@ -1,193 +0,0 @@ -package net.lab1024.smartadmin.service.common.security; - -import com.google.common.collect.Lists; -import lombok.extern.slf4j.Slf4j; -import net.lab1024.smartadmin.service.common.annoation.NoNeedLogin; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.MapUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.mvc.method.RequestMappingInfo; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * [ ] - * - * @author 罗伊 - * @date 2021/8/31 10:20 - */ -@Slf4j -@Component -public class SecurityUrlMatchers { - - @Value("${project.module}") - private String scanPackage; - - @Autowired - private WebApplicationContext applicationContext; - - /** - * 匿名访问URL - */ - private List anonymousUrl = Lists.newArrayList(); - /** - * 忽略的URL(注意,加入忽略的URL,无法进入Security filter) - */ - private List ignoreUrl = Lists.newArrayList(); - - /** - * 需要登录的 - */ - private List authenticatedUrl = Lists.newArrayList(); - - /** - * 方法的请求路径 - */ - private Map> methodUrlMap = new HashMap<>(); - - /** - * 获取忽略的URL集合 - * - * @return - */ - public synchronized List getIgnoreUrl() { - if (CollectionUtils.isNotEmpty(ignoreUrl)) { - return ignoreUrl; - } - ignoreUrl.add("/swagger-ui.html"); - ignoreUrl.add("/swagger-resources/**"); - ignoreUrl.add("/webjars/**"); - ignoreUrl.add("/*/api-docs"); - log.info("忽略URL:{}", ignoreUrl); - return ignoreUrl; - } - - /** - * 需要登录认证的URL集合 - * - * @return - */ - public synchronized List getAuthenticatedUrlList() { - if (CollectionUtils.isNotEmpty(authenticatedUrl)) { - return authenticatedUrl; - } - authenticatedUrl.add("/admin/**"); - log.info("认证URL:{}", authenticatedUrl); - return authenticatedUrl; - } - - /** - * 获取无需登录可以匿名访问的url信息 - * - * @return - */ - private synchronized List getAnonymousUrl() { - if (CollectionUtils.isNotEmpty(anonymousUrl)) { - return anonymousUrl; - } - Map> methodSetMap = this.getMethodUrlMap(); - for (Entry> entry : methodSetMap.entrySet()) { - Method method = entry.getKey(); - NoNeedLogin noNeedLogin = method.getAnnotation(NoNeedLogin.class); - if (null == noNeedLogin) { - continue; - } - anonymousUrl.addAll(entry.getValue()); - } - log.info("匿名URL:{}", anonymousUrl); - return anonymousUrl; - } - - /** - * 获取每个方法的请求路径 - * - * @return - */ - private synchronized Map> getMethodUrlMap() { - if (MapUtils.isNotEmpty(methodUrlMap)) { - return methodUrlMap; - } - RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class); - //获取url与类和方法的对应信息 - Map map = mapping.getHandlerMethods(); - for (Entry entry : map.entrySet()) { - RequestMappingInfo requestMappingInfo = entry.getKey(); - Set urls = requestMappingInfo.getPatternsCondition().getPatterns(); - if (CollectionUtils.isEmpty(urls)) { - continue; - } - HandlerMethod handlerMethod = entry.getValue(); - methodUrlMap.put(handlerMethod.getMethod(), urls); - } - return methodUrlMap; - } - - public Set getMethodUrl(Method method) { - return methodUrlMap.get(method); - } - - /** - * 获取需要校验的包路径 - * - * @return - */ - public String getValidPackage() { - return scanPackage; - } - - /** - * 不需要权限校验的 - * - * @return - */ - public List getNoValidUrl() { - List noValidUrl = Lists.newArrayList(); - noValidUrl.addAll(this.getIgnoreUrl()); - noValidUrl.addAll(this.getAnonymousUrl()); - return noValidUrl; - } - - /** - * 获取需要忽略的url集合 - * - * @return - */ - public String[] getIgnoreUrlArray() { - List ignoreUrl = this.getIgnoreUrl(); - String[] ignoreUrlArray = ignoreUrl.toArray(new String[ignoreUrl.size()]); - return ignoreUrlArray; - } - - /** - * 获取需要匿名访问的url集合 - * - * @return - */ - public String[] getAnonymousUrlArray() { - List anonymousUrl = this.getAnonymousUrl(); - String[] anonymousUrlArray = anonymousUrl.toArray(new String[anonymousUrl.size()]); - return anonymousUrlArray; - } - - /** - * 获取需要认证的url集合 - * - * @return - */ - public String[] getAuthenticatedUrlArray() { - List authenticatedUrl = this.getAuthenticatedUrlList(); - String[] authenticatedUrlArray = authenticatedUrl.toArray(new String[authenticatedUrl.size()]); - return authenticatedUrlArray; - } - -} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/util/SmartRequestUtil.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/util/SmartRequestUtil.java index 39d58133..559e807f 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/util/SmartRequestUtil.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/common/util/SmartRequestUtil.java @@ -2,8 +2,6 @@ package net.lab1024.smartadmin.service.common.util; import lombok.extern.slf4j.Slf4j; import net.lab1024.smartadmin.service.module.system.login.domain.RequestEmployee; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; /** * @author 罗伊 @@ -11,39 +9,27 @@ import org.springframework.security.core.context.SecurityContextHolder; @Slf4j public class SmartRequestUtil { - /** - * 获取用户信息 - * - * @return - */ + private static final ThreadLocal LOCAL_USER = new ThreadLocal<>(); + + public static void setRequestEmployee(RequestEmployee requestEmployee) { + LOCAL_USER.set(requestEmployee); + } + public static RequestEmployee getRequestEmployee() { - try { - return (RequestEmployee) getAuthentication().getPrincipal(); - } catch (Exception e) { - log.error("获取用户信息异常:{}", e); - } - return null; + return LOCAL_USER.get(); } - /** - * 获取用户认证信息 - * - * @return - */ - public static Authentication getAuthentication() { - return SecurityContextHolder.getContext().getAuthentication(); - } - - /** - * 获取用户id - * - * @return - */ public static Long getRequestEmployeeId() { - RequestEmployee requestUser = getRequestEmployee(); - if (null == requestUser) { + RequestEmployee requestEmployee = getRequestEmployee(); + if (null == requestEmployee) { return null; } - return requestUser.getEmployeeId(); + return requestEmployee.getEmployeeId(); } + + public static void remove() { + LOCAL_USER.remove(); + } + + } diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SaTokenConfigure.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SaTokenConfigure.java new file mode 100644 index 00000000..954bf4bf --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SaTokenConfigure.java @@ -0,0 +1,107 @@ +package net.lab1024.smartadmin.service.config; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; +import cn.dev33.satoken.interceptor.SaRouteInterceptor; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.smartadmin.service.common.annoation.NoNeedLogin; +import net.lab1024.smartadmin.service.common.constant.UrlPrefixConst; +import net.lab1024.smartadmin.service.common.util.SmartRequestUtil; +import net.lab1024.smartadmin.service.module.system.login.domain.LoginUserDetail; +import net.lab1024.smartadmin.service.module.system.login.service.JwtService; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * [ ] + * + * @author yandanyang + * @date 2021/10/13 16:36 + */ +@Slf4j +@Configuration +public class SaTokenConfigure implements WebMvcConfigurer { + + @Value("${access-control-allow-origin}") + private String accessControlAllowOrigin; + + @Autowired + private JwtService jwtService; + + /** + * 注册Sa-Token的注解拦截器,打开注解式鉴权功能 + * + * @param registry + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + + registry.addInterceptor(new SaRouteInterceptor((req, res, handler) -> { + //跨域 + this.crossDomainConfig((HttpServletResponse) res.getSource()); + boolean isHandlerMethod = handler instanceof HandlerMethod; + if (!isHandlerMethod) { + return; + } + HttpServletRequest request = (HttpServletRequest) req.getSource(); + String uri = request.getRequestURI(); + String contextPath = request.getContextPath(); + String target = uri.replaceFirst(contextPath, ""); + //忽略URL + if (target.startsWith("/swagger")) { + return; + } + //支持服务重启后 token依然有效 ,如果实现SaTokenDao 为redis或第三方持久化存储的话可放弃此部分代码 + String tokenValue = StpUtil.getTokenValue(); + LoginUserDetail employeeLoginInfoDTO = jwtService.getEmployeeLoginBO(tokenValue); + if (employeeLoginInfoDTO != null) { + StpUtil.stpLogic.saveTokenToIdMapping(tokenValue, employeeLoginInfoDTO.getEmployeeId(), SaManager.getConfig().getTimeout()); + SmartRequestUtil.setRequestEmployee(employeeLoginInfoDTO); + return; + } + //无需登录 + NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class); + if (noNeedLogin != null) { + return; + } + //其他情况验证登录 + StpUtil.checkLogin(); + })).addPathPatterns(UrlPrefixConst.SYSTEM + "/**"); + registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns(UrlPrefixConst.SYSTEM + "/**"); + } + + /** + * 配置跨域 + * + * @param response + */ + private void crossDomainConfig(HttpServletResponse response) { + response.setHeader("Access-Control-Allow-Origin", accessControlAllowOrigin); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); + response.setHeader("Access-Control-Expose-Headers", "*"); + response.setHeader("Access-Control-Allow-Headers", "Authentication,Origin, X-Requested-With, Content-Type, " + "Accept, x-access-token"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires ", "-1"); + } + + + @Autowired + public void rewriteSaStrategy() { + // 重写 Token 生成策略 + SaStrategy.me.createToken = (loginId, loginType) -> { + return jwtService.generateJwtToken(NumberUtils.toLong(loginId.toString())); + }; + } +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SecurityConfig.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SecurityConfig.java deleted file mode 100644 index ac311361..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SecurityConfig.java +++ /dev/null @@ -1,100 +0,0 @@ -package net.lab1024.smartadmin.service.config; - -import net.lab1024.smartadmin.service.common.security.SecurityUrlMatchers; -import net.lab1024.smartadmin.service.filter.SecurityTokenFilter; -import net.lab1024.smartadmin.service.common.security.SecurityAuthenticationFailHandler; -import net.lab1024.smartadmin.service.module.system.login.service.JwtService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; - -import java.util.List; - -/** - * Spring Security - * - * @author zhuoda - * @date 2021/8/3 17:50 - */ -@Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - @Value("${access-control-allow-origin}") - private String accessControlAllowOrigin; - /** - * url - */ - @Autowired - private SecurityUrlMatchers securityUrlMatchers; - - /** - * 获取TOKEN 解析类 - */ - @Autowired - private JwtService loginTokenService; - - /** - * 跨域配置 - * - * @return - */ - @Bean - public CorsFilter corsFilter() { - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - CorsConfiguration config = new CorsConfiguration(); - config.setAllowCredentials(true); - // 设置访问源地址 - config.addAllowedOriginPattern(accessControlAllowOrigin); - // 设置访问源请求头 - config.addAllowedHeader("*"); - // 设置访问源请求方法 - config.addAllowedMethod("*"); - // 对接口配置跨域设置 - source.registerCorsConfiguration("/**", config); - return new CorsFilter(source); - } - - @Override - protected void configure(HttpSecurity httpSecurity) throws Exception { - ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry interceptUrlRegistry = httpSecurity - // CSRF禁用,因为不使用session - .csrf().disable() - // 认证失败处理类 - .exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationFailHandler()).and() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - // 过滤请求 - .authorizeRequests(); - //可以匿名登录的URL - String [] anonymousUrlArray = securityUrlMatchers.getAnonymousUrlArray(); - interceptUrlRegistry.antMatchers(anonymousUrlArray).permitAll(); - - //登录的URL - String [] authenticatedUrlArray = securityUrlMatchers.getAuthenticatedUrlArray(); - interceptUrlRegistry.antMatchers(authenticatedUrlArray).authenticated(); - - httpSecurity.addFilterBefore(new SecurityTokenFilter(loginTokenService), UsernamePasswordAuthenticationFilter.class); - httpSecurity.addFilterBefore(corsFilter(), SecurityTokenFilter.class); - } - - @Override - public void configure(WebSecurity web) { - // 忽略url - WebSecurity.IgnoredRequestConfigurer ignoring = web.ignoring(); - List ignoreUrlListList = securityUrlMatchers.getIgnoreUrl(); - for (String url : ignoreUrlListList) { - ignoring.antMatchers(url); - } - } - - -} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SecurityMethodConfig.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SecurityMethodConfig.java deleted file mode 100644 index 876c3234..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/SecurityMethodConfig.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.lab1024.smartadmin.service.config; - -import net.lab1024.smartadmin.service.common.security.SecurityMetadataSource; -import net.lab1024.smartadmin.service.common.security.SecurityUrlMatchers; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory; -import org.springframework.security.access.method.MethodSecurityMetadataSource; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; - -/** - * 此类用于注入自己的 method校验 - * SmartSecurityMetadataSource - * @author zhuoda - * @date 2021-08-31 0:01 - */ -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SecurityMethodConfig extends GlobalMethodSecurityConfiguration { - - @Autowired - private SecurityUrlMatchers securityUrlMatchers; - - @Override - public MethodSecurityMetadataSource customMethodSecurityMetadataSource(){ - ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(this.getExpressionHandler()); - return new SecurityMetadataSource(attributeFactory, securityUrlMatchers); - } -} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/filter/SecurityTokenFilter.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/filter/SecurityTokenFilter.java deleted file mode 100644 index a0e94e72..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/filter/SecurityTokenFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.lab1024.smartadmin.service.filter; - -import net.lab1024.smartadmin.service.common.constant.RequestHeaderConst; -import net.lab1024.smartadmin.service.module.system.login.domain.LoginUserDetail; -import net.lab1024.smartadmin.service.module.system.login.service.JwtService; -import org.apache.commons.lang3.StringUtils; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -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; - -/** - * [ ] - * 注意此处不能 加入@Component - * 否则对应ignoreUrl的相关请求 将会进入此Filter,并会覆盖CorsFilter - * - * @author 罗伊 - * @date - */ - -public class SecurityTokenFilter extends OncePerRequestFilter { - - private JwtService loginTokenService; - - public SecurityTokenFilter(JwtService loginTokenService) { - this.loginTokenService = loginTokenService; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) - throws ServletException, IOException { - //需要做token校验, 消息头的token优先于请求query参数的token - String xHeaderToken = request.getHeader(RequestHeaderConst.TOKEN); - String xRequestToken = request.getParameter(RequestHeaderConst.TOKEN); - String xAccessToken = null != xHeaderToken ? xHeaderToken : xRequestToken; - if (StringUtils.isBlank(xAccessToken)) { - chain.doFilter(request, response); - return; - } - //清理spring security - SecurityContextHolder.clearContext(); - LoginUserDetail loginUserDetail = loginTokenService.getEmployeeLoginBO(xAccessToken); - if (null != loginUserDetail) { - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUserDetail, null, loginUserDetail.getAuthorities()); - authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - } - // 若未给予spring security上下文用户授权 则会授权失败 进入AuthenticationEntryPointImpl - chain.doFilter(request, response); - } -} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/handler/GlobalExceptionHandler.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/handler/GlobalExceptionHandler.java index 7ee40e66..fa93f160 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/handler/GlobalExceptionHandler.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/handler/GlobalExceptionHandler.java @@ -1,19 +1,18 @@ package net.lab1024.smartadmin.service.handler; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; import lombok.extern.slf4j.Slf4j; import net.lab1024.smartadmin.service.common.code.SystemErrorCode; import net.lab1024.smartadmin.service.common.code.UserErrorCode; import net.lab1024.smartadmin.service.common.domain.ResponseDTO; import net.lab1024.smartadmin.service.common.domain.SystemEnvironment; -import net.lab1024.smartadmin.service.common.enumeration.SystemEnvironmentEnum; import net.lab1024.smartadmin.service.common.exception.BusinessException; import org.springframework.beans.TypeMismatchException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.security.access.AccessDeniedException; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; -import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -81,14 +80,26 @@ public class GlobalExceptionHandler { * 权限异常 */ @ResponseBody - @ExceptionHandler({AccessDeniedException.class}) - public ResponseDTO permissionExceptionHandler(AccessDeniedException e) { + @ExceptionHandler({NotPermissionException.class}) + public ResponseDTO permissionExceptionHandler(NotPermissionException e) { if (!systemEnvironment.isProd()) { log.error("全局参数异常,URL:{}", getCurrentRequestUrl(), e); } return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } + /** + * 未登录异常 + */ + @ResponseBody + @ExceptionHandler({NotLoginException.class}) + public ResponseDTO notLoginExceptionHandler(NotLoginException e) { + if (!systemEnvironment.isProd()) { + log.error("全局参数异常,URL:{}", getCurrentRequestUrl(), e); + } + return ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID); + } + /** * 业务异常 */ diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/domain/LoginUserDetail.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/domain/LoginUserDetail.java index 9b2ba95a..25a50c15 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/domain/LoginUserDetail.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/domain/LoginUserDetail.java @@ -1,10 +1,6 @@ package net.lab1024.smartadmin.service.module.system.login.domain; import lombok.Data; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Collection; /** * 员工登陆BO @@ -13,63 +9,11 @@ import java.util.Collection; * @date 2021/8/4 11:15 */ @Data -public class LoginUserDetail extends RequestEmployee implements UserDetails { +public class LoginUserDetail extends RequestEmployee { /** * 登录密码 */ private String loginPassword; - @Override - public Collection getAuthorities() { - return null; - } - - @Override - public String getPassword() { - return this.getLoginPassword(); - } - - @Override - public String getUsername() { - return this.getLoginName(); - } - - /** - * 账户是否未过期,过期无法验证 - */ - @Override - public boolean isAccountNonExpired() { - return true; - } - - /** - * 指定用户是否解锁,锁定的用户无法进行身份验证 - * - * @return - */ - @Override - public boolean isAccountNonLocked() { - return true; - } - - /** - * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 - * - * @return - */ - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - /** - * 是否可用 ,禁用的用户不能身份验证 - * - * @return - */ - @Override - public boolean isEnabled() { - return true; - } } diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/JwtService.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/JwtService.java index 0631d57f..561caed9 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/JwtService.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/JwtService.java @@ -1,5 +1,6 @@ package net.lab1024.smartadmin.service.module.system.login.service; +import cn.dev33.satoken.SaManager; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @@ -21,11 +22,6 @@ import java.util.Date; @Service public class JwtService { - /** - * 默认 token 过期时间 1 天 - */ - private static final int EXPIRE_SECONDS = 24 * 3600; - /** * 默认 jwt key */ @@ -53,7 +49,7 @@ public class JwtService { return Jwts.builder() .setClaims(jwtClaims) .setIssuedAt(new Date(nowTimeMilli)) - .setExpiration(new Date(nowTimeMilli + EXPIRE_SECONDS * 1000)) + .setExpiration(new Date(SaManager.getConfig().getTimeout() * 1000)) .signWith(SignatureAlgorithm.HS512, JWT_KEY) .compact(); } diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/LoginService.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/LoginService.java index 679151bc..f21a002c 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/LoginService.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/login/service/LoginService.java @@ -1,5 +1,6 @@ package net.lab1024.smartadmin.service.module.system.login.service; +import cn.dev33.satoken.stp.StpUtil; import lombok.extern.slf4j.Slf4j; import net.lab1024.smartadmin.service.common.code.UserErrorCode; import net.lab1024.smartadmin.service.common.constant.StringConst; @@ -86,7 +87,9 @@ public class LoginService { } // 生成 登录token - String token = jwtService.generateJwtToken(employeeEntity.getEmployeeId()); + Long employeeId = employeeEntity.getEmployeeId(); + StpUtil.login(employeeId); + String token = StpUtil.getTokenValue(); // 获取前端菜单以及功能权限 MenuLoginBO menuLoginBORespDTO = menuEmployeeService.queryMenuTreeByEmployeeId(employeeEntity.getEmployeeId()); // 查询部门 diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuEmployeeService.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuEmployeeService.java index c3ab099e..978d2049 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuEmployeeService.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuEmployeeService.java @@ -115,7 +115,7 @@ public class MenuEmployeeService { * @param roleIdList * @return */ - private List getMenuByRoleIdList(List roleIdList, Boolean isSuperman) { + public List getMenuByRoleIdList(List roleIdList, Boolean isSuperman) { if (CollectionUtils.isEmpty(roleIdList)) { return Lists.newArrayList(); } diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuPermissionService.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuPermissionService.java index eaff507a..274dae3c 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuPermissionService.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/system/menu/service/MenuPermissionService.java @@ -1,6 +1,5 @@ package net.lab1024.smartadmin.service.module.system.menu.service; -import net.lab1024.smartadmin.service.common.security.SecurityMetadataSource; import net.lab1024.smartadmin.service.common.util.SmartRequestUtil; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -18,7 +17,7 @@ import javax.servlet.http.HttpServletRequest; * @author lihaifan * @date 2021/8/5 17:14 */ -@Service(SecurityMetadataSource.PRIVILEGE_CHECK_NAME) +@Service public class MenuPermissionService { @Autowired diff --git a/admin-api/java-api/src/main/resources/dev/application.properties b/admin-api/java-api/src/main/resources/dev/application.properties index 2cbfe8d8..8fd708bf 100644 --- a/admin-api/java-api/src/main/resources/dev/application.properties +++ b/admin-api/java-api/src/main/resources/dev/application.properties @@ -94,3 +94,12 @@ heart-beat.intervalTime=300000 ######################### cache config ######################### spring.cache.type=caffeine +######################### sa-token config ######################### +# token名称 (同时也是cookie名称) +sa-token.token-name=x-access-token +# token有效期,单位s 默认30天, -1代表永不过期 +sa-token.timeout=2592000 +# 是否输出banner +sa-token.is-print=false +# 是否输出操作日志 +sa-token.is-log=false \ No newline at end of file