From 6c5e9884bacffdd16223f596427ea1dde67b9d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=B2=90?= Date: Sat, 27 Aug 2022 23:59:02 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AE=89=E5=85=A8=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=EF=BC=8C=E7=A7=BB=E9=99=A4oauth2.0=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8springsecurity=E4=BB=A3=E6=9B=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maku/security/event/AuthenticationEvents.java | 41 +++++++ .../maku/security/filter/ValidateCodeFilter.java | 58 --------- .../net/maku/security/service/CaptchaService.java | 72 ----------- .../security/service/FastClientDetailsService.java | 82 ------------- .../security/service/FastUserDetailsService.java | 30 ++--- .../service/RedisAuthorizationCodeServices.java | 32 ----- fast-boot-system/src/main/resources/auth.yml | 11 +- fast-framework/pom.xml | 127 +++++++++---------- .../maku/framework/common/cache/RedisCache.java | 134 +++++++++++++++++++++ .../net/maku/framework/common/cache/RedisKeys.java | 24 ++++ .../net/maku/framework/common/utils/RedisKeys.java | 24 ---- .../maku/framework/common/utils/RedisUtils.java | 126 ------------------- .../framework/security/cache/TokenStoreCache.java | 33 +++++ .../security/config/AuthorizationServerConfig.java | 76 ------------ .../framework/security/config/PermitResource.java | 10 +- .../security/config/ResourceServerConfig.java | 50 -------- .../framework/security/config/SecurityConfig.java | 69 +++++++++++ .../security/config/TokenStoreConfig.java | 25 ---- .../security/config/WebSecurityConfig.java | 61 ---------- .../exception/FastAuthenticationException.java | 18 --- .../security/exception/FastOAuth2Exception.java | 31 ----- .../FastWebResponseExceptionTranslator.java | 78 ------------ .../security/filter/AuthenticationTokenFilter.java | 57 +++++++++ .../handler/UserAuthenticationFailureHandler.java | 31 ----- .../security/token/FastTokenEnhancer.java | 34 ------ .../maku/framework/security/user/UserDetail.java | 13 +- .../maku/framework/security/utils/TokenUtils.java | 33 +++++ fast-framework/src/main/resources/auth.yml | 10 ++ 28 files changed, 480 insertions(+), 910 deletions(-) create mode 100644 fast-boot-system/src/main/java/net/maku/security/event/AuthenticationEvents.java delete mode 100644 fast-boot-system/src/main/java/net/maku/security/filter/ValidateCodeFilter.java delete mode 100644 fast-boot-system/src/main/java/net/maku/security/service/CaptchaService.java delete mode 100644 fast-boot-system/src/main/java/net/maku/security/service/FastClientDetailsService.java delete mode 100644 fast-boot-system/src/main/java/net/maku/security/service/RedisAuthorizationCodeServices.java create mode 100644 fast-framework/src/main/java/net/maku/framework/common/cache/RedisCache.java create mode 100644 fast-framework/src/main/java/net/maku/framework/common/cache/RedisKeys.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/common/utils/RedisKeys.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/common/utils/RedisUtils.java create mode 100644 fast-framework/src/main/java/net/maku/framework/security/cache/TokenStoreCache.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/config/AuthorizationServerConfig.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/config/ResourceServerConfig.java create mode 100644 fast-framework/src/main/java/net/maku/framework/security/config/SecurityConfig.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/config/TokenStoreConfig.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/config/WebSecurityConfig.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/exception/FastAuthenticationException.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/exception/FastOAuth2Exception.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/exception/FastWebResponseExceptionTranslator.java create mode 100644 fast-framework/src/main/java/net/maku/framework/security/filter/AuthenticationTokenFilter.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/handler/UserAuthenticationFailureHandler.java delete mode 100644 fast-framework/src/main/java/net/maku/framework/security/token/FastTokenEnhancer.java create mode 100644 fast-framework/src/main/java/net/maku/framework/security/utils/TokenUtils.java create mode 100644 fast-framework/src/main/resources/auth.yml diff --git a/fast-boot-system/src/main/java/net/maku/security/event/AuthenticationEvents.java b/fast-boot-system/src/main/java/net/maku/security/event/AuthenticationEvents.java new file mode 100644 index 0000000..fcdb6a3 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/security/event/AuthenticationEvents.java @@ -0,0 +1,41 @@ +package net.maku.security.event; + +import lombok.AllArgsConstructor; +import net.maku.framework.common.constant.Constant; +import net.maku.framework.security.user.UserDetail; +import net.maku.system.enums.LoginOperationEnum; +import net.maku.system.service.SysLogLoginService; +import org.springframework.context.event.EventListener; +import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.stereotype.Component; + +/** + * 认证事件处理 + * + * @author 阿沐 babamu@126.com + */ +@Component +@AllArgsConstructor +public class AuthenticationEvents { + private final SysLogLoginService sysLogLoginService; + + @EventListener + public void onSuccess(AuthenticationSuccessEvent event) { + // 用户信息 + UserDetail user = (UserDetail) event.getAuthentication().getPrincipal(); + + // 保存登录日志 + sysLogLoginService.save(user.getUsername(), Constant.SUCCESS, LoginOperationEnum.LOGIN_SUCCESS.getValue()); + } + + @EventListener + public void onFailure(AbstractAuthenticationFailureEvent event) { + // 用户名 + String username = (String) event.getAuthentication().getPrincipal(); + + // 保存登录日志 + sysLogLoginService.save(username, Constant.FAIL, LoginOperationEnum.ACCOUNT_FAIL.getValue()); + } + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/security/filter/ValidateCodeFilter.java b/fast-boot-system/src/main/java/net/maku/security/filter/ValidateCodeFilter.java deleted file mode 100644 index 764113d..0000000 --- a/fast-boot-system/src/main/java/net/maku/security/filter/ValidateCodeFilter.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.maku.security.filter; - -import lombok.AllArgsConstructor; -import net.maku.framework.security.exception.FastAuthenticationException; -import net.maku.framework.security.handler.UserAuthenticationFailureHandler; -import net.maku.security.service.CaptchaService; -import org.springframework.security.core.AuthenticationException; -import org.springframework.stereotype.Component; -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; - -/** - * 验证码过滤器 - * - * @author 阿沐 babamu@126.com - */ -@Component -@AllArgsConstructor -public class ValidateCodeFilter extends OncePerRequestFilter { - private final static String OAUTH_TOKEN_URL = "/sys/oauth/token"; - private final CaptchaService captchaService; - private final UserAuthenticationFailureHandler authenticationFailureHandler; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - if(request.getServletPath().equals(OAUTH_TOKEN_URL) - && request.getMethod().equalsIgnoreCase("POST") - && "password".equalsIgnoreCase(request.getParameter("grant_type"))) { - try { - // 校验验证码 - validate(request); - }catch (AuthenticationException e) { - // 失败处理器 - authenticationFailureHandler.onAuthenticationFailure(request, response, e); - return; - } - } - - filterChain.doFilter(request, response); - } - - private void validate(HttpServletRequest request) { - String key = request.getParameter("key"); - String captcha = request.getParameter("captcha"); - - boolean flag = captchaService.validate(key, captcha); - - if(!flag) { - throw new FastAuthenticationException("验证码错误"); - } - } -} diff --git a/fast-boot-system/src/main/java/net/maku/security/service/CaptchaService.java b/fast-boot-system/src/main/java/net/maku/security/service/CaptchaService.java deleted file mode 100644 index f895533..0000000 --- a/fast-boot-system/src/main/java/net/maku/security/service/CaptchaService.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.maku.security.service; - -import cn.hutool.core.util.StrUtil; -import com.wf.captcha.SpecCaptcha; -import com.wf.captcha.base.Captcha; -import lombok.AllArgsConstructor; -import net.maku.framework.common.utils.RedisKeys; -import net.maku.framework.common.utils.RedisUtils; -import org.springframework.stereotype.Service; - -/** - * 验证码 - * - * @author 阿沐 babamu@126.com - */ -@Service -@AllArgsConstructor -public class CaptchaService { - private final RedisUtils redisUtils; - - /** - * 生成验证码 - * @param key key - * @return 返回base64图片验证码 - */ - public String generate(String key) { - // 生成验证码 - SpecCaptcha captcha = new SpecCaptcha(150, 40); - captcha.setLen(5); - captcha.setCharType(Captcha.TYPE_DEFAULT); - - // 保存到缓存 - key = RedisKeys.getCaptchaKey(key); - redisUtils.set(key, captcha.text(), 300); - - return captcha.toBase64(); - } - - /** - * 验证码效验 - * @param key key - * @param code 验证码 - * @return true:成功 false:失败 - */ - public boolean validate(String key, String code) { - if(StrUtil.isBlank(key) || StrUtil.isBlank(code)){ - return false; - } - - // 获取验证码 - String captcha = getCache(key); - - // 效验成功 - if(code.equalsIgnoreCase(captcha)){ - return true; - } - - return false; - } - - - private String getCache(String key){ - key = RedisKeys.getCaptchaKey(key); - String captcha = (String)redisUtils.get(key); - // 删除验证码 - if(captcha != null){ - redisUtils.delete(key); - } - - return captcha; - } -} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/security/service/FastClientDetailsService.java b/fast-boot-system/src/main/java/net/maku/security/service/FastClientDetailsService.java deleted file mode 100644 index 64623a6..0000000 --- a/fast-boot-system/src/main/java/net/maku/security/service/FastClientDetailsService.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.maku.security.service; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; -import lombok.AllArgsConstructor; -import net.maku.framework.common.utils.JsonUtils; -import net.maku.system.dao.SysOauthClientDao; -import net.maku.system.entity.SysOauthClientEntity; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.ClientDetailsService; -import org.springframework.security.oauth2.provider.ClientRegistrationException; -import org.springframework.security.oauth2.provider.client.BaseClientDetails; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; - -import java.util.Map; - -/** - * ClientDetailsService - * - * @author 阿沐 babamu@126.com - */ -@Service -@AllArgsConstructor -public class FastClientDetailsService implements ClientDetailsService { - private final SysOauthClientDao sysOauthClientDao; - - @Override - public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException { - SysOauthClientEntity oauthClient = sysOauthClientDao.getByClientId(clientId); - - return clientDetailsMapper(oauthClient); - } - - private ClientDetails clientDetailsMapper(SysOauthClientEntity entity) { - BaseClientDetails client = new BaseClientDetails(); - client.setClientId(entity.getClientId()); - // 密码前追加 {noop} 前缀,表示密码是明文 - client.setClientSecret(String.format("{noop}%s", entity.getClientSecret())); - - if (ArrayUtil.isNotEmpty(entity.getAuthorizedGrantTypes())) { - client.setAuthorizedGrantTypes(CollUtil.newArrayList(entity.getAuthorizedGrantTypes())); - } - - if (StrUtil.isNotBlank(entity.getAuthorities())) { - client.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(entity.getAuthorities())); - } - - if (StrUtil.isNotBlank(entity.getResourceIds())) { - client.setResourceIds(StringUtils.commaDelimitedListToSet(entity.getResourceIds())); - } - - if (StrUtil.isNotBlank(entity.getWebServerRedirectUri())) { - client.setRegisteredRedirectUri(StringUtils.commaDelimitedListToSet(entity.getWebServerRedirectUri())); - } - - if (StrUtil.isNotBlank(entity.getScope())) { - client.setScope(StringUtils.commaDelimitedListToSet(entity.getScope())); - } - - if (StrUtil.isNotBlank(entity.getAutoapprove())) { - client.setAutoApproveScopes(StringUtils.commaDelimitedListToSet(entity.getAutoapprove())); - } - - if (entity.getAccessTokenValidity() != null) { - client.setAccessTokenValiditySeconds(entity.getAccessTokenValidity()); - } - - if (entity.getRefreshTokenValidity() != null) { - client.setRefreshTokenValiditySeconds(entity.getRefreshTokenValidity()); - } - - if (StrUtil.isNotBlank(entity.getAdditionalInformation())) { - Map map = JsonUtils.parseObject(entity.getAdditionalInformation(), Map.class); - client.setAdditionalInformation(map); - } - - return client; - } -} diff --git a/fast-boot-system/src/main/java/net/maku/security/service/FastUserDetailsService.java b/fast-boot-system/src/main/java/net/maku/security/service/FastUserDetailsService.java index af13946..9402b38 100644 --- a/fast-boot-system/src/main/java/net/maku/security/service/FastUserDetailsService.java +++ b/fast-boot-system/src/main/java/net/maku/security/service/FastUserDetailsService.java @@ -1,8 +1,6 @@ package net.maku.security.service; import lombok.AllArgsConstructor; -import net.maku.framework.common.exception.ErrorCode; -import net.maku.framework.common.exception.FastException; import net.maku.framework.security.user.UserDetail; import net.maku.system.convert.SysUserConvert; import net.maku.system.dao.SysRoleDao; @@ -13,18 +11,14 @@ import net.maku.system.enums.DataScopeEnum; import net.maku.system.enums.UserStatusEnum; import net.maku.system.service.SysMenuService; import net.maku.system.service.SysOrgService; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; /** * UserDetailsService @@ -43,15 +37,15 @@ public class FastUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { SysUserEntity userEntity = sysUserDao.getByUsername(username); - if(userEntity == null) { - throw new FastException(ErrorCode.ACCOUNT_PASSWORD_ERROR); + if (userEntity == null) { + throw new UsernameNotFoundException("用户名或密码错误"); } // 转换成UserDetail对象 UserDetail userDetail = SysUserConvert.INSTANCE.convertDetail(userEntity); // 账号不可用 - if(userEntity.getStatus() == UserStatusEnum.DISABLE.getValue()){ + if (userEntity.getStatus() == UserStatusEnum.DISABLE.getValue()) { userDetail.setEnabled(false); } @@ -60,15 +54,15 @@ public class FastUserDetailsService implements UserDetailsService { userDetail.setDataScopeList(dataScopeList); // 用户权限列表 - Set authorities = getUserAuthority(userDetail); - userDetail.setAuthorities(authorities); + Set authoritySet = sysMenuService.getUserAuthority(userDetail); + userDetail.setAuthoritySet(authoritySet); return userDetail; } - private List getDataScope(UserDetail userDetail){ + private List getDataScope(UserDetail userDetail) { Integer dataScope = sysRoleDao.getDataScopeByUserId(userDetail.getId()); - if (dataScope == null){ + if (dataScope == null) { return new ArrayList<>(); } @@ -98,14 +92,4 @@ public class FastUserDetailsService implements UserDetailsService { return new ArrayList<>(); } - private Set getUserAuthority(UserDetail user) { - // 获取用户权限标识 - Set permsSet = sysMenuService.getUserAuthority(user); - - // 封装权限标识 - Set authorities = new HashSet<>(); - authorities.addAll(permsSet.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); - - return authorities; - } } diff --git a/fast-boot-system/src/main/java/net/maku/security/service/RedisAuthorizationCodeServices.java b/fast-boot-system/src/main/java/net/maku/security/service/RedisAuthorizationCodeServices.java deleted file mode 100644 index 65add04..0000000 --- a/fast-boot-system/src/main/java/net/maku/security/service/RedisAuthorizationCodeServices.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.maku.security.service; - -import lombok.AllArgsConstructor; -import net.maku.framework.common.utils.RedisKeys; -import net.maku.framework.common.utils.RedisUtils; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices; -import org.springframework.stereotype.Service; - -/** - * 基于Redis的授权码模式 - * - * @author 阿沐 babamu@126.com - */ -@Service -@AllArgsConstructor -public class RedisAuthorizationCodeServices extends RandomValueAuthorizationCodeServices { - private final RedisUtils redisUtils; - - @Override - protected void store(String code, OAuth2Authentication authentication) { - String key = RedisKeys.getOauthCode(code); - redisUtils.set(key, authentication); - } - - @Override - public OAuth2Authentication remove(String code) { - String key = RedisKeys.getOauthCode(code); - return (OAuth2Authentication)redisUtils.get(key); - } - -} \ No newline at end of file diff --git a/fast-boot-system/src/main/resources/auth.yml b/fast-boot-system/src/main/resources/auth.yml index a8a14e3..b024308 100644 --- a/fast-boot-system/src/main/resources/auth.yml +++ b/fast-boot-system/src/main/resources/auth.yml @@ -1,12 +1,5 @@ auth: ignore_urls: - - /actuator/** - - /v3/api-docs/** - - /webjars/** - - /swagger/** - - /swagger-resources/** - - /swagger-ui.html - - /swagger-ui/** - - /doc.html - - /sys/oauth/captcha + - /sys/auth/captcha + - /sys/auth/login - /upload/** \ No newline at end of file diff --git a/fast-framework/pom.xml b/fast-framework/pom.xml index a475d92..f9e9384 100644 --- a/fast-framework/pom.xml +++ b/fast-framework/pom.xml @@ -1,73 +1,60 @@ - - - net.maku - fast-boot - ${revision} - - 4.0.0 - fast-framework - jar + + + net.maku + fast-boot + ${revision} + + 4.0.0 + fast-framework + jar - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-data-redis - - - org.springframework.boot - spring-boot-starter-security - - - kotlin-stdlib-jdk7 - org.jetbrains.kotlin - - - kotlin-stdlib-jdk8 - org.jetbrains.kotlin - - - - - org.springframework.security.oauth - spring-security-oauth2 - - - mysql - mysql-connector-java - - - com.dameng - DmJdbcDriver18 - - - com.baomidou - mybatis-plus-boot-starter - - - org.springdoc - springdoc-openapi-ui - - - cn.hutool - hutool-all - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-security + + + mysql + mysql-connector-java + + + com.dameng + DmJdbcDriver18 + + + com.baomidou + mybatis-plus-boot-starter + + + org.springdoc + springdoc-openapi-ui + + + cn.hutool + hutool-all + \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/common/cache/RedisCache.java b/fast-framework/src/main/java/net/maku/framework/common/cache/RedisCache.java new file mode 100644 index 0000000..e8ccb89 --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/common/cache/RedisCache.java @@ -0,0 +1,134 @@ +package net.maku.framework.common.cache; + +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Redis Cache + * + * @author 阿沐 babamu@126.com + */ +@Component +public class RedisCache { + @Resource + private RedisTemplate redisTemplate; + + /** + * 默认过期时长为24小时,单位:秒 + */ + public final static long DEFAULT_EXPIRE = 60 * 60 * 24L; + /** + * 过期时长为1小时,单位:秒 + */ + public final static long HOUR_ONE_EXPIRE = 60 * 60 * 1L; + /** + * 过期时长为6小时,单位:秒 + */ + public final static long HOUR_SIX_EXPIRE = 60 * 60 * 6L; + /** + * 不设置过期时长 + */ + public final static long NOT_EXPIRE = -1L; + + public void set(String key, Object value, long expire) { + redisTemplate.opsForValue().set(key, value); + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public void set(String key, Object value) { + set(key, value, DEFAULT_EXPIRE); + } + + public Object get(String key, long expire) { + Object value = redisTemplate.opsForValue().get(key); + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + return value; + } + + public Object get(String key) { + return get(key, NOT_EXPIRE); + } + + public Long increment(String key) { + return redisTemplate.opsForValue().increment(key); + } + + public Boolean hasKey(String key) { + return redisTemplate.hasKey(key); + } + + public void delete(String key) { + redisTemplate.delete(key); + } + + public void delete(Collection keys) { + redisTemplate.delete(keys); + } + + public Object hGet(String key, String field) { + return redisTemplate.opsForHash().get(key, field); + } + + public Map hGetAll(String key) { + HashOperations hashOperations = redisTemplate.opsForHash(); + return hashOperations.entries(key); + } + + public void hMSet(String key, Map map) { + hMSet(key, map, DEFAULT_EXPIRE); + } + + public void hMSet(String key, Map map, long expire) { + redisTemplate.opsForHash().putAll(key, map); + + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public void hSet(String key, String field, Object value) { + hSet(key, field, value, DEFAULT_EXPIRE); + } + + public void hSet(String key, String field, Object value, long expire) { + redisTemplate.opsForHash().put(key, field, value); + + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public void expire(String key, long expire) { + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + + public void hDel(String key, Object... fields) { + redisTemplate.opsForHash().delete(key, fields); + } + + public void leftPush(String key, Object value) { + leftPush(key, value, DEFAULT_EXPIRE); + } + + public void leftPush(String key, Object value, long expire) { + redisTemplate.opsForList().leftPush(key, value); + + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public Object rightPop(String key) { + return redisTemplate.opsForList().rightPop(key); + } +} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/common/cache/RedisKeys.java b/fast-framework/src/main/java/net/maku/framework/common/cache/RedisKeys.java new file mode 100644 index 0000000..8527bd5 --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/common/cache/RedisKeys.java @@ -0,0 +1,24 @@ +package net.maku.framework.common.cache; + +/** + * Redis Key管理 + * + * @author 阿沐 babamu@126.com + */ +public class RedisKeys { + + /** + * 验证码Key + */ + public static String getCaptchaKey(String key) { + return "sys:captcha:" + key; + } + + /** + * accessToken Key + */ + public static String getAccessTokenKey(String accessToken) { + return "sys:access:" + accessToken; + } + +} diff --git a/fast-framework/src/main/java/net/maku/framework/common/utils/RedisKeys.java b/fast-framework/src/main/java/net/maku/framework/common/utils/RedisKeys.java deleted file mode 100644 index 185c283..0000000 --- a/fast-framework/src/main/java/net/maku/framework/common/utils/RedisKeys.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.maku.framework.common.utils; - -/** - * Redis Key管理 - * - * @author 阿沐 babamu@126.com - */ -public class RedisKeys { - - /** - * 验证码Key - */ - public static String getCaptchaKey(String key) { - return "sys:captcha:" + key; - } - - /** - * 授权码Key - */ - public static String getOauthCode(String code) { - return "oauth:code:" + code; - } - -} diff --git a/fast-framework/src/main/java/net/maku/framework/common/utils/RedisUtils.java b/fast-framework/src/main/java/net/maku/framework/common/utils/RedisUtils.java deleted file mode 100644 index cbcec14..0000000 --- a/fast-framework/src/main/java/net/maku/framework/common/utils/RedisUtils.java +++ /dev/null @@ -1,126 +0,0 @@ -package net.maku.framework.common.utils; - -import org.springframework.data.redis.core.HashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * Redis工具类 - * - * @author 阿沐 babamu@126.com - */ -@Component -public class RedisUtils { - @Resource - private RedisTemplate redisTemplate; - - /** 默认过期时长为24小时,单位:秒 */ - public final static long DEFAULT_EXPIRE = 60 * 60 * 24L; - /** 过期时长为1小时,单位:秒 */ - public final static long HOUR_ONE_EXPIRE = 60 * 60 * 1L; - /** 过期时长为6小时,单位:秒 */ - public final static long HOUR_SIX_EXPIRE = 60 * 60 * 6L; - /** 不设置过期时长 */ - public final static long NOT_EXPIRE = -1L; - - public void set(String key, Object value, long expire){ - redisTemplate.opsForValue().set(key, value); - if(expire != NOT_EXPIRE){ - expire(key, expire); - } - } - - public void set(String key, Object value){ - set(key, value, DEFAULT_EXPIRE); - } - - public Object get(String key, long expire) { - Object value = redisTemplate.opsForValue().get(key); - if(expire != NOT_EXPIRE){ - expire(key, expire); - } - return value; - } - - public Object get(String key) { - return get(key, NOT_EXPIRE); - } - - public Long increment(String key){ - return redisTemplate.opsForValue().increment(key); - } - - public Boolean hasKey(String key){ - return redisTemplate.hasKey(key); - } - - public void delete(String key) { - redisTemplate.delete(key); - } - - public void delete(Collection keys) { - redisTemplate.delete(keys); - } - - public Object hGet(String key, String field) { - return redisTemplate.opsForHash().get(key, field); - } - - public Map hGetAll(String key){ - HashOperations hashOperations = redisTemplate.opsForHash(); - return hashOperations.entries(key); - } - - public void hMSet(String key, Map map){ - hMSet(key, map, DEFAULT_EXPIRE); - } - - public void hMSet(String key, Map map, long expire){ - redisTemplate.opsForHash().putAll(key, map); - - if(expire != NOT_EXPIRE){ - expire(key, expire); - } - } - - public void hSet(String key, String field, Object value) { - hSet(key, field, value, DEFAULT_EXPIRE); - } - - public void hSet(String key, String field, Object value, long expire) { - redisTemplate.opsForHash().put(key, field, value); - - if(expire != NOT_EXPIRE){ - expire(key, expire); - } - } - - public void expire(String key, long expire){ - redisTemplate.expire(key, expire, TimeUnit.SECONDS); - } - - public void hDel(String key, Object... fields){ - redisTemplate.opsForHash().delete(key, fields); - } - - public void leftPush(String key, Object value){ - leftPush(key, value, DEFAULT_EXPIRE); - } - - public void leftPush(String key, Object value, long expire){ - redisTemplate.opsForList().leftPush(key, value); - - if(expire != NOT_EXPIRE){ - expire(key, expire); - } - } - - public Object rightPop(String key){ - return redisTemplate.opsForList().rightPop(key); - } -} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/security/cache/TokenStoreCache.java b/fast-framework/src/main/java/net/maku/framework/security/cache/TokenStoreCache.java new file mode 100644 index 0000000..3be26ed --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/security/cache/TokenStoreCache.java @@ -0,0 +1,33 @@ +package net.maku.framework.security.cache; + +import lombok.AllArgsConstructor; +import net.maku.framework.common.cache.RedisCache; +import net.maku.framework.common.cache.RedisKeys; +import net.maku.framework.security.user.UserDetail; +import org.springframework.stereotype.Component; + +/** + * 认证 Cache + * + * @author 阿沐 babamu@126.com + */ +@Component +@AllArgsConstructor +public class TokenStoreCache { + private final RedisCache redisCache; + + public void saveUser(String accessToken, UserDetail user) { + String key = RedisKeys.getAccessTokenKey(accessToken); + redisCache.set(key, user); + } + + public UserDetail getUser(String accessToken) { + String key = RedisKeys.getAccessTokenKey(accessToken); + return (UserDetail) redisCache.get(key); + } + + public void deleteUser(String accessToken) { + String key = RedisKeys.getAccessTokenKey(accessToken); + redisCache.delete(key); + } +} diff --git a/fast-framework/src/main/java/net/maku/framework/security/config/AuthorizationServerConfig.java b/fast-framework/src/main/java/net/maku/framework/security/config/AuthorizationServerConfig.java deleted file mode 100644 index 142a9f6..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/config/AuthorizationServerConfig.java +++ /dev/null @@ -1,76 +0,0 @@ -package net.maku.framework.security.config; - -import lombok.AllArgsConstructor; -import net.maku.framework.security.exception.FastWebResponseExceptionTranslator; -import net.maku.framework.security.token.FastTokenEnhancer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; -import org.springframework.security.oauth2.provider.ClientDetailsService; -import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; -import org.springframework.security.oauth2.provider.token.TokenStore; - -/** - * 认证服务器配置 - * - * @author 阿沐 babamu@126.com - */ -@Configuration -@AllArgsConstructor -@EnableAuthorizationServer -public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { - private final AuthenticationManager authenticationManager; - private final ClientDetailsService fastClientDetailsService; - private final UserDetailsService userDetailsService; - private final AuthorizationCodeServices redisAuthorizationCodeServices; - private final TokenStore tokenStore; - - /** - * 配置客户端信息 - */ - @Override - public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - clients.withClientDetails(fastClientDetailsService); - } - - @Override - public void configure(AuthorizationServerEndpointsConfigurer endpoints) { - endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.DELETE); - // 密码模式 - endpoints.authenticationManager(authenticationManager); - // 支持刷新令牌 - endpoints.userDetailsService(userDetailsService); - // 令牌管理 - endpoints.tokenStore(tokenStore); - // 令牌增强 - endpoints.tokenEnhancer(tokenEnhancer()); - // 登录或者鉴权失败时的返回信息 - endpoints.exceptionTranslator(new FastWebResponseExceptionTranslator()); - // 配置授权码模式,存放在Redis中 - endpoints.authorizationCodeServices(redisAuthorizationCodeServices); - // 自定义登录地址 - endpoints.pathMapping("/oauth/token","/sys/oauth/token"); - } - - @Bean - public TokenEnhancer tokenEnhancer() { - return new FastTokenEnhancer(); - } - - @Override - public void configure(AuthorizationServerSecurityConfigurer security) { - security - .allowFormAuthenticationForClients() - .tokenKeyAccess("permitAll()") // 匿名可访问/oauth/token_key - .checkTokenAccess("isAuthenticated()") // 认证后可访问/oauth/check_token - ; - } -} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/security/config/PermitResource.java b/fast-framework/src/main/java/net/maku/framework/security/config/PermitResource.java index 8ff764a..c7f3438 100644 --- a/fast-framework/src/main/java/net/maku/framework/security/config/PermitResource.java +++ b/fast-framework/src/main/java/net/maku/framework/security/config/PermitResource.java @@ -21,10 +21,10 @@ import java.util.Properties; @Component public class PermitResource { /** - * 指定被 spring security oauth2.0 忽略的URL + * 指定被 spring security 忽略的URL */ @SneakyThrows - public List getPermitList(){ + public List getPermitList() { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources("classpath*:auth.yml"); String key = "auth.ignore_urls"; @@ -32,16 +32,16 @@ public class PermitResource { return getPropertiesList(key, resources); } - private List getPropertiesList(String key, Resource... resources){ + private List getPropertiesList(String key, Resource... resources) { List list = new ArrayList<>(); // 解析资源文件 - for(Resource resource : resources) { + for (Resource resource : resources) { Properties properties = loadYamlProperties(resource); for (Map.Entry entry : properties.entrySet()) { String tmpKey = StringUtils.substringBefore(entry.getKey().toString(), "["); - if(tmpKey.equalsIgnoreCase(key)){ + if (tmpKey.equalsIgnoreCase(key)) { list.add(entry.getValue().toString()); } } diff --git a/fast-framework/src/main/java/net/maku/framework/security/config/ResourceServerConfig.java b/fast-framework/src/main/java/net/maku/framework/security/config/ResourceServerConfig.java deleted file mode 100644 index ca5cf45..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/config/ResourceServerConfig.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.maku.framework.security.config; - -import lombok.AllArgsConstructor; -import net.maku.framework.security.exception.SecurityAuthenticationEntryPoint; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; -import org.springframework.security.oauth2.provider.token.TokenStore; - -import java.util.List; - -/** - * 资源服务器配置 - * - * @author 阿沐 babamu@126.com - */ -@Configuration -@AllArgsConstructor -@EnableResourceServer -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class ResourceServerConfig extends ResourceServerConfigurerAdapter { - private final TokenStore tokenStore; - private final PermitResource permitResource; - - @Override - public void configure(ResourceServerSecurityConfigurer resources) { - resources.tokenStore(tokenStore); - - resources.authenticationEntryPoint(new SecurityAuthenticationEntryPoint()); - } - - @Override - public void configure(HttpSecurity http) throws Exception { - // 忽略授权的地址列表 - List permitList = permitResource.getPermitList(); - String [] permits = permitList.toArray(new String[permitList.size()]); - - http - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeRequests() - .antMatchers(permits).permitAll() - .anyRequest().authenticated() - ; - } -} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/security/config/SecurityConfig.java b/fast-framework/src/main/java/net/maku/framework/security/config/SecurityConfig.java new file mode 100644 index 0000000..5b05d19 --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/security/config/SecurityConfig.java @@ -0,0 +1,69 @@ +package net.maku.framework.security.config; + +import lombok.AllArgsConstructor; +import net.maku.framework.security.exception.SecurityAuthenticationEntryPoint; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationEventPublisher; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.util.List; + +@Configuration +@AllArgsConstructor +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig { + private final UserDetailsService userDetailsService; + private final OncePerRequestFilter authenticationTokenFilter; + private final PermitResource permitResource; + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + return new DefaultAuthenticationEventPublisher(applicationEventPublisher); + } + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // 忽略授权的地址列表 + List permitList = permitResource.getPermitList(); + String[] permits = permitList.toArray(new String[0]); + + http + .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class) + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and().authorizeRequests() + .antMatchers(permits).permitAll() + .anyRequest().authenticated() + .and().userDetailsService(userDetailsService) + .exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationEntryPoint()) + .and().headers().frameOptions().disable() + .and().csrf().disable() + ; + + return http.build(); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return web -> web.ignoring().antMatchers(HttpMethod.OPTIONS); + } +} diff --git a/fast-framework/src/main/java/net/maku/framework/security/config/TokenStoreConfig.java b/fast-framework/src/main/java/net/maku/framework/security/config/TokenStoreConfig.java deleted file mode 100644 index 44ff06e..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/config/TokenStoreConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.maku.framework.security.config; - -import lombok.AllArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.security.oauth2.provider.token.TokenStore; -import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; - -/** - * TokenStore - * - * @author 阿沐 babamu@126.com - */ -@Configuration -@AllArgsConstructor -public class TokenStoreConfig { - private final RedisConnectionFactory redisConnectionFactory; - - @Bean - public TokenStore tokenStore() { - // 使用redis存储token - return new RedisTokenStore(redisConnectionFactory); - } -} diff --git a/fast-framework/src/main/java/net/maku/framework/security/config/WebSecurityConfig.java b/fast-framework/src/main/java/net/maku/framework/security/config/WebSecurityConfig.java deleted file mode 100644 index e738faf..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/config/WebSecurityConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.maku.framework.security.config; - -import lombok.AllArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -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.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.filter.OncePerRequestFilter; - -/** - * Spring Security配置 - * - * @author 阿沐 babamu@126.com - */ -@AllArgsConstructor -@EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - private final UserDetailsService userDetailsService; - private final OncePerRequestFilter validateCodeFilter; - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService); - } - - /** - * 密码模式需要 - */ - @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception{ - return super.authenticationManager(); - } - - @Override - public void configure(HttpSecurity http) throws Exception { - http - .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) - .formLogin() - .loginPage("/login") - .loginProcessingUrl("/login") - .and() - .authorizeRequests() - .antMatchers("/oauth/authorize").authenticated() - .anyRequest().permitAll() - .and().headers().frameOptions().disable() - .and().csrf().disable() - ; - } - - @Override - public void configure(WebSecurity web) { - web.ignoring().antMatchers(HttpMethod.OPTIONS); - } -} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/security/exception/FastAuthenticationException.java b/fast-framework/src/main/java/net/maku/framework/security/exception/FastAuthenticationException.java deleted file mode 100644 index 0f952a7..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/exception/FastAuthenticationException.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.maku.framework.security.exception; - -import org.springframework.security.core.AuthenticationException; - -/** - * 认证异常类 - * - * @author 阿沐 babamu@126.com - */ -public class FastAuthenticationException extends AuthenticationException { - public FastAuthenticationException(String msg, Throwable t) { - super(msg, t); - } - - public FastAuthenticationException(String msg) { - super(msg); - } -} diff --git a/fast-framework/src/main/java/net/maku/framework/security/exception/FastOAuth2Exception.java b/fast-framework/src/main/java/net/maku/framework/security/exception/FastOAuth2Exception.java deleted file mode 100644 index bf7d7d7..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/exception/FastOAuth2Exception.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.maku.framework.security.exception; - -import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; - -/** - * 自定义异常 - * - * @author 阿沐 babamu@126.com - */ -public class FastOAuth2Exception extends OAuth2Exception { - private String msg; - - public FastOAuth2Exception(String msg) { - super(msg); - this.msg = msg; - } - - public FastOAuth2Exception(String msg, Throwable e) { - super(msg, e); - this.msg = msg; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - -} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/security/exception/FastWebResponseExceptionTranslator.java b/fast-framework/src/main/java/net/maku/framework/security/exception/FastWebResponseExceptionTranslator.java deleted file mode 100644 index b3862b3..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/exception/FastWebResponseExceptionTranslator.java +++ /dev/null @@ -1,78 +0,0 @@ -package net.maku.framework.security.exception; - -import net.maku.framework.common.exception.ErrorCode; -import net.maku.framework.common.utils.Result; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.exceptions.ClientAuthenticationException; -import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException; -import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; -import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; -import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; -import org.springframework.security.web.util.ThrowableAnalyzer; -import org.springframework.stereotype.Component; -import org.springframework.web.HttpRequestMethodNotSupportedException; - -/** - * 登录或者鉴权失败时的返回信息 - * - * @author 阿沐 babamu@126.com - */ -@Component -public class FastWebResponseExceptionTranslator implements WebResponseExceptionTranslator { - private final ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer(); - - @Override - public ResponseEntity translate(Exception e) { - Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e); - - Exception exception = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain); - if (exception != null) { - return handleOAuth2Exception(new FastOAuth2Exception(e.getMessage(), e)); - } - - exception = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain); - if (exception != null) { - return handleOAuth2Exception(new FastOAuth2Exception(exception.getMessage(), exception)); - } - - exception = (InvalidGrantException) throwableAnalyzer.getFirstThrowableOfType(InvalidGrantException.class, causeChain); - if (exception != null) { - return handleOAuth2Exception(new FastOAuth2Exception(exception.getMessage(), exception)); - } - - exception = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain); - if (exception != null) { - return handleOAuth2Exception(new FastOAuth2Exception(exception.getMessage(), exception)); - } - - exception = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain); - if (exception != null) { - return handleOAuth2Exception((OAuth2Exception) exception); - } - - return handleOAuth2Exception(new FastOAuth2Exception(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e)); - } - - private ResponseEntity handleOAuth2Exception(OAuth2Exception e) { - int status = e.getHttpErrorCode(); - HttpHeaders headers = new HttpHeaders(); - headers.set(HttpHeaders.CACHE_CONTROL, "no-store"); - headers.set(HttpHeaders.PRAGMA, "no-cache"); - if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) { - headers.set(HttpHeaders.WWW_AUTHENTICATE, String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary())); - } - - if (e instanceof ClientAuthenticationException) { - return new ResponseEntity<>(e, headers, HttpStatus.valueOf(status)); - } - Result result = Result.error(ErrorCode.ACCOUNT_PASSWORD_ERROR); - - return new ResponseEntity(result, headers, HttpStatus.OK); - } -} diff --git a/fast-framework/src/main/java/net/maku/framework/security/filter/AuthenticationTokenFilter.java b/fast-framework/src/main/java/net/maku/framework/security/filter/AuthenticationTokenFilter.java new file mode 100644 index 0000000..596d3de --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/security/filter/AuthenticationTokenFilter.java @@ -0,0 +1,57 @@ +package net.maku.framework.security.filter; + +import lombok.AllArgsConstructor; +import net.maku.framework.security.cache.TokenStoreCache; +import net.maku.framework.security.user.UserDetail; +import net.maku.framework.security.utils.TokenUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +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; + +/** + * 认证过滤器 + * + * @author 阿沐 babamu@126.com + */ +@Component +@AllArgsConstructor +public class AuthenticationTokenFilter extends OncePerRequestFilter { + private final TokenStoreCache tokenStoreCache; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + String accessToken = TokenUtils.getAccessToken(request); + // accessToken为空,表示未登录 + if (StringUtils.isBlank(accessToken)) { + chain.doFilter(request, response); + return; + } + + // 获取登录用户信息 + UserDetail user = tokenStoreCache.getUser(accessToken); + if (user == null) { + chain.doFilter(request, response); + return; + } + + // 用户存在 + Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); + + // 新建 SecurityContext + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(authentication); + SecurityContextHolder.setContext(context); + + chain.doFilter(request, response); + } +} diff --git a/fast-framework/src/main/java/net/maku/framework/security/handler/UserAuthenticationFailureHandler.java b/fast-framework/src/main/java/net/maku/framework/security/handler/UserAuthenticationFailureHandler.java deleted file mode 100644 index cc25d78..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/handler/UserAuthenticationFailureHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.maku.framework.security.handler; - -import lombok.SneakyThrows; -import net.maku.framework.common.utils.HttpContextUtils; -import net.maku.framework.common.utils.JsonUtils; -import net.maku.framework.common.utils.Result; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * 认证失败处理器 - * - * @author 阿沐 babamu@126.com - */ -@Component -public class UserAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { - - @SneakyThrows - @Override - public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) { - response.setContentType("application/json;charset=UTF-8"); - response.setHeader("Access-Control-Allow-Credentials", "true"); - response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); - - response.getWriter().write(JsonUtils.toJsonString(Result.error(e.getMessage()))); - } -} diff --git a/fast-framework/src/main/java/net/maku/framework/security/token/FastTokenEnhancer.java b/fast-framework/src/main/java/net/maku/framework/security/token/FastTokenEnhancer.java deleted file mode 100644 index 82578d7..0000000 --- a/fast-framework/src/main/java/net/maku/framework/security/token/FastTokenEnhancer.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.maku.framework.security.token; - -import net.maku.framework.common.utils.Result; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; - -import java.util.HashMap; -import java.util.Map; - -/** - * 令牌 - * - * @author 阿沐 babamu@126.com - */ -public class FastTokenEnhancer implements TokenEnhancer { - - @Override - public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { - if(accessToken instanceof DefaultOAuth2AccessToken){ - DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken; - - // 增加额外信息 - Map info = new HashMap<>(); - info.put("code", new Result<>().getCode()); - token.setAdditionalInformation(info); - - return token; - } - - return accessToken; - } -} \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/security/user/UserDetail.java b/fast-framework/src/main/java/net/maku/framework/security/user/UserDetail.java index f6753be..82fa82d 100644 --- a/fast-framework/src/main/java/net/maku/framework/security/user/UserDetail.java +++ b/fast-framework/src/main/java/net/maku/framework/security/user/UserDetail.java @@ -1,13 +1,15 @@ package net.maku.framework.security.user; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; -import java.util.Date; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** * 登录用户信息 @@ -29,10 +31,10 @@ public class UserDetail implements UserDetails { private Long orgId; private Integer status; private Integer superAdmin; - private Date createTime; + /** * 数据权限范围 - * + *

* null:表示全部数据权限 */ private List dataScopeList; @@ -55,11 +57,12 @@ public class UserDetail implements UserDetails { /** * 拥有权限集合 */ - private Set authorities; + private Set authoritySet; @Override + @JsonIgnore public Collection getAuthorities() { - return this.authorities; + return authoritySet.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet()); } @Override diff --git a/fast-framework/src/main/java/net/maku/framework/security/utils/TokenUtils.java b/fast-framework/src/main/java/net/maku/framework/security/utils/TokenUtils.java new file mode 100644 index 0000000..0a62648 --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/security/utils/TokenUtils.java @@ -0,0 +1,33 @@ +package net.maku.framework.security.utils; + +import cn.hutool.core.lang.UUID; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; + +/** + * Token 工具类 + * + * @author 阿沐 babamu@126.com + */ +public class TokenUtils { + + /** + * 生成 AccessToken + */ + public static String generator() { + return UUID.fastUUID().toString(true); + } + + /** + * 获取 AccessToken + */ + public static String getAccessToken(HttpServletRequest request) { + String accessToken = request.getHeader("Authorization"); + if (StringUtils.isBlank(accessToken)) { + accessToken = request.getParameter("access_token"); + } + + return accessToken; + } +} diff --git a/fast-framework/src/main/resources/auth.yml b/fast-framework/src/main/resources/auth.yml new file mode 100644 index 0000000..bb6867f --- /dev/null +++ b/fast-framework/src/main/resources/auth.yml @@ -0,0 +1,10 @@ +auth: + ignore_urls: + - /actuator/** + - /v3/api-docs/** + - /webjars/** + - /swagger/** + - /swagger-resources/** + - /swagger-ui.html + - /swagger-ui/** + - /doc.html \ No newline at end of file