().eq(User::getUserMobile, user.getUserMobile())) > 0) {
- // 该电话号码已存在
- throw new YamiShopBindException("该电话号码已存在");
- }
- String userId = IdUtil.simpleUUID();
- user.setUserId(userId);
- userMapper.insert(user);
- } else {
- if (appConnect != null&& StrUtil.isBlank(user.getPic())) {
- User userParam = new User();
- userParam.setUserId(user.getUserId());
- userParam.setModifyTime(new Date());
- userParam.setPic(appConnect.getImageUrl());
- userService.updateById(userParam);
- }
- }
- if (appConnect == null) {
- // 避免重复插入数据
- if (appConnectMapper.getByBizUserId(user.getUserId(), appId) != null) {
- return user;
- }
- appConnect = new AppConnect();
- appConnect.setUserId(user.getUserId());
- appConnect.setNickName(user.getNickName());
- appConnect.setImageUrl(user.getPic());
-
- // 0表示是系统的用户,不是第三方的
- appConnect.setAppId(appId);
- appConnectMapper.insert(appConnect);
- } else if (StrUtil.isBlank(appConnect.getUserId()) || Objects.isNull(appId)) {
- appConnect.setAppId(appId);
- appConnect.setUserId(user.getUserId());
- appConnect.setUserId(user.getUserId());
- appConnectMapper.updateById(appConnect);
- }
-
- return user;
- }
-}
diff --git a/yami-shop-security/src/main/java/com/yami/shop/security/token/MpAuthenticationToken.java b/yami-shop-security/src/main/java/com/yami/shop/security/token/MpAuthenticationToken.java
deleted file mode 100644
index 011e90f..0000000
--- a/yami-shop-security/src/main/java/com/yami/shop/security/token/MpAuthenticationToken.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
-package com.yami.shop.security.token;
-
-import lombok.NoArgsConstructor;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * 二维码Token
- */
-@NoArgsConstructor
-public class MpAuthenticationToken extends MyAuthenticationToken {
-
-
- public MpAuthenticationToken(UserDetails principal, Object credentials) {
- super(principal, credentials, principal.getAuthorities());
- }
-}
diff --git a/yami-shop-security/src/main/java/com/yami/shop/security/token/MyAuthenticationToken.java b/yami-shop-security/src/main/java/com/yami/shop/security/token/MyAuthenticationToken.java
deleted file mode 100644
index e15b676..0000000
--- a/yami-shop-security/src/main/java/com/yami/shop/security/token/MyAuthenticationToken.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
-package com.yami.shop.security.token;
-
-import lombok.Getter;
-import lombok.Setter;
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-
-import java.util.Collection;
-
-/**
- * 自定义AbstractAuthenticationToken,
- */
-@Getter
-@Setter
-public class MyAuthenticationToken extends AbstractAuthenticationToken {
-
- private static final long serialVersionUID = 110L;
- protected Object principal;
- protected Object credentials;
- protected Boolean debugger;
-
- public MyAuthenticationToken() {
- super(null);
- }
- /**
- * This constructor should only be used by AuthenticationManager or AuthenticationProvider
- * implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} = true)
- * token token.
- *
- * @param principal
- * @param credentials
- * @param authorities
- */
- public MyAuthenticationToken(Object principal, Object credentials, Collection extends GrantedAuthority> authorities) {
- super(authorities);
- this.principal = principal;
- this.credentials = credentials;
- super.setAuthenticated(true);
- }
- public MyAuthenticationToken(Object principal, Object credentials) {
- super(null);
- this.principal = principal;
- this.credentials = credentials;
- this.setAuthenticated(false);
- }
-
-
- @Override
- public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
- if(isAuthenticated) {
- throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
- } else {
- super.setAuthenticated(false);
- }
- }
-
- @Override
- public void eraseCredentials() {
- super.eraseCredentials();
- this.credentials = null;
- }
-
-}
diff --git a/yami-shop-security/src/main/java/com/yami/shop/security/util/SecurityUtils.java b/yami-shop-security/src/main/java/com/yami/shop/security/util/SecurityUtils.java
deleted file mode 100644
index b1bbbe5..0000000
--- a/yami-shop-security/src/main/java/com/yami/shop/security/util/SecurityUtils.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
-package com.yami.shop.security.util;
-
-
-import com.yami.shop.security.exception.UnauthorizedExceptionBase;
-import com.yami.shop.security.service.YamiSysUser;
-import com.yami.shop.security.service.YamiUser;
-import lombok.experimental.UtilityClass;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-/**
- * 安全工具类
- *
- * @author L.cm
- */
-@UtilityClass
-public class SecurityUtils {
- /**
- * 获取Authentication
- */
- public Authentication getAuthentication() {
- return SecurityContextHolder.getContext().getAuthentication();
- }
-
- /**
- * 获取用户
- */
- public YamiUser getUser() {
- Authentication authentication = getAuthentication();
- Object principal = authentication.getPrincipal();
- if (principal instanceof YamiUser) {
- return (YamiUser) principal;
- }
- throw new UnauthorizedExceptionBase("无法获取普通用户信息");
- }
-
- /**
- * 获取系统用户
- */
- public YamiSysUser getSysUser() {
- Authentication authentication = getAuthentication();
- Object principal = authentication.getPrincipal();
- if (principal instanceof YamiSysUser) {
- return (YamiSysUser) principal;
- }
- throw new UnauthorizedExceptionBase("无法获取系统用户信息");
- }
-}
diff --git a/yami-shop-security/src/main/java/com/yami/shop/security/util/YamiTokenServices.java b/yami-shop-security/src/main/java/com/yami/shop/security/util/YamiTokenServices.java
deleted file mode 100644
index acf6bfa..0000000
--- a/yami-shop-security/src/main/java/com/yami/shop/security/util/YamiTokenServices.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
-package com.yami.shop.security.util;
-
-import java.util.Date;
-import java.util.Set;
-import java.util.UUID;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken;
-import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
-import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
-import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
-import org.springframework.security.oauth2.common.OAuth2AccessToken;
-import org.springframework.security.oauth2.common.OAuth2RefreshToken;
-import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
-import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
-import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
-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.OAuth2Authentication;
-import org.springframework.security.oauth2.provider.OAuth2Request;
-import org.springframework.security.oauth2.provider.TokenRequest;
-import org.springframework.security.oauth2.provider.token.*;
-import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.Assert;
-
-/**
- * Base implementation for token services using random UUID values for the access token and refresh token values. The
- * main extension point for customizations is the {@link TokenEnhancer} which will be called after the access and
- * refresh tokens have been generated but before they are stored.
- *
- * Persistence is delegated to a {@code TokenStore} implementation and customization of the access token to a
- * {@link TokenEnhancer}.
- *
- * @author Ryan Heaton
- * @author Luke Taylor
- * @author Dave Syer
- * @author LGH
- */
-public class YamiTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,
- ConsumerTokenServices, InitializingBean {
-
- // default 30 days.
- private int refreshTokenValiditySeconds = 60 * 60 * 24 * 30;
-
- // default 12 hours.
- private int accessTokenValiditySeconds = 60 * 60 * 12;
-
- private boolean supportRefreshToken = false;
-
- private boolean reuseRefreshToken = true;
-
- private TokenStore tokenStore;
-
- private ClientDetailsService clientDetailsService;
-
- private TokenEnhancer accessTokenEnhancer;
-
- private AuthenticationManager authenticationManager;
-
- /**
- * Initialize these token services. If no random generator is set, one will be created.
- */
- @Override
- public void afterPropertiesSet() throws Exception {
- Assert.notNull(tokenStore, "tokenStore must be set");
- }
-
- @Transactional(rollbackFor = Exception.class)
- @Override
- public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) {
-
-// OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
- OAuth2RefreshToken refreshToken = null;
- // 如果有token,直接删除,更新token,避免出现缓存问题
-// if (existingAccessToken != null) {
-// if (existingAccessToken.getRefreshToken() != null) {
-// refreshToken = existingAccessToken.getRefreshToken();
-// // The token store could remove the refresh token when the
-// // access token is removed, but we want to
-// // be sure...
-// tokenStore.removeRefreshToken(refreshToken);
-// }
-// tokenStore.removeAccessToken(existingAccessToken);
-//
-// }
-
- // Only create a new refresh token if there wasn't an existing one
- // associated with an expired access token.
- // Clients might be holding existing refresh tokens, so we re-use it in
- // the case that the old access token
- // expired.
- if (refreshToken == null) {
- refreshToken = createRefreshToken(authentication);
- }
- // But the refresh token itself might need to be re-issued if it has
- // expired.
- else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
- ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
- if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
- refreshToken = createRefreshToken(authentication);
- }
- }
-
- OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
- tokenStore.storeAccessToken(accessToken, authentication);
- // In case it was modified
- refreshToken = accessToken.getRefreshToken();
- if (refreshToken != null) {
- tokenStore.storeRefreshToken(refreshToken, authentication);
- }
- return accessToken;
-
- }
-
- @Override
- @Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class}, rollbackFor = Exception.class)
- public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
- throws AuthenticationException {
-
- if (!supportRefreshToken) {
- throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
- }
-
- OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
- if (refreshToken == null) {
- throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
- }
-
- OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
- if (this.authenticationManager != null && !authentication.isClientOnly()) {
- // The client has already been authenticated, but the user authentication might be old now, so give it a
- // chance to re-authenticate.
- Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());
- user = authenticationManager.authenticate(user);
- Object details = authentication.getDetails();
- authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
- authentication.setDetails(details);
- }
- String clientId = authentication.getOAuth2Request().getClientId();
- if (clientId == null || !clientId.equals(tokenRequest.getClientId())) {
- throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);
- }
-
- // clear out any access tokens already associated with the refresh
- // token.
- tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);
-
- if (isExpired(refreshToken)) {
- tokenStore.removeRefreshToken(refreshToken);
- throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
- }
-
- authentication = createRefreshedAuthentication(authentication, tokenRequest);
-
- if (!reuseRefreshToken) {
- tokenStore.removeRefreshToken(refreshToken);
- refreshToken = createRefreshToken(authentication);
- }
-
- OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
- tokenStore.storeAccessToken(accessToken, authentication);
- if (!reuseRefreshToken) {
- tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
- }
- return accessToken;
- }
-
- @Override
- public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
- return tokenStore.getAccessToken(authentication);
- }
-
- /**
- * Create a refreshed authentication.
- *
- * @param authentication The authentication.
- * @param request The scope for the refreshed token.
- * @return The refreshed authentication.
- * @throws InvalidScopeException If the scope requested is invalid or wider than the original scope.
- */
- private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, TokenRequest request) {
- OAuth2Authentication narrowed = authentication;
- Set scope = request.getScope();
- OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);
- if (scope != null && !scope.isEmpty()) {
- Set originalScope = clientAuth.getScope();
- if (originalScope == null || !originalScope.containsAll(scope)) {
- throw new InvalidScopeException("Unable to narrow the scope of the client authentication to " + scope
- + ".", originalScope);
- }
- else {
- clientAuth = clientAuth.narrowScope(scope);
- }
- }
- narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());
- return narrowed;
- }
-
- protected boolean isExpired(OAuth2RefreshToken refreshToken) {
- if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
- ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;
- return expiringToken.getExpiration() == null
- || System.currentTimeMillis() > expiringToken.getExpiration().getTime();
- }
- return false;
- }
-
- @Override
- public OAuth2AccessToken readAccessToken(String accessToken) {
- return tokenStore.readAccessToken(accessToken);
- }
-
- @Override
- public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,
- InvalidTokenException {
- OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
- if (accessToken == null) {
- throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
- }
- else if (accessToken.isExpired()) {
- tokenStore.removeAccessToken(accessToken);
- throw new InvalidTokenException("Access token expired: " + accessTokenValue);
- }
-
- OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
- if (result == null) {
- // in case of race condition
- throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
- }
- if (clientDetailsService != null) {
- String clientId = result.getOAuth2Request().getClientId();
- try {
- clientDetailsService.loadClientByClientId(clientId);
- }
- catch (ClientRegistrationException e) {
- throw new InvalidTokenException("Client not valid: " + clientId, e);
- }
- }
- return result;
- }
-
- public String getClientId(String tokenValue) {
- OAuth2Authentication authentication = tokenStore.readAuthentication(tokenValue);
- if (authentication == null) {
- throw new InvalidTokenException("Invalid access token: " + tokenValue);
- }
- OAuth2Request clientAuth = authentication.getOAuth2Request();
- if (clientAuth == null) {
- throw new InvalidTokenException("Invalid access token (no client id): " + tokenValue);
- }
- return clientAuth.getClientId();
- }
-
- @Override
- public boolean revokeToken(String tokenValue) {
- OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
- if (accessToken == null) {
- return false;
- }
- if (accessToken.getRefreshToken() != null) {
- tokenStore.removeRefreshToken(accessToken.getRefreshToken());
- }
- tokenStore.removeAccessToken(accessToken);
- return true;
- }
-
- private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
- if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
- return null;
- }
- int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
- String value = UUID.randomUUID().toString();
- if (validitySeconds > 0) {
- return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
- + (validitySeconds * 1000L)));
- }
- return new DefaultOAuth2RefreshToken(value);
- }
-
- private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
- DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
- int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
- if (validitySeconds > 0) {
- token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
- }
- token.setRefreshToken(refreshToken);
- token.setScope(authentication.getOAuth2Request().getScope());
-
- return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
- }
-
- /**
- * The access token validity period in seconds
- *
- * @param clientAuth the current authorization request
- * @return the access token validity period in seconds
- */
- protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
- if (clientDetailsService != null) {
- ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
- Integer validity = client.getAccessTokenValiditySeconds();
- if (validity != null) {
- return validity;
- }
- }
- return accessTokenValiditySeconds;
- }
-
- /**
- * The refresh token validity period in seconds
- *
- * @param clientAuth the current authorization request
- * @return the refresh token validity period in seconds
- */
- protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
- if (clientDetailsService != null) {
- ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
- Integer validity = client.getRefreshTokenValiditySeconds();
- if (validity != null) {
- return validity;
- }
- }
- return refreshTokenValiditySeconds;
- }
-
- /**
- * Is a refresh token supported for this client (or the global setting if
- * {@link #setClientDetailsService(ClientDetailsService) clientDetailsService} is not set.
- *
- * @param clientAuth the current authorization request
- * @return boolean to indicate if refresh token is supported
- */
- protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
- if (clientDetailsService != null) {
- ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
- return client.getAuthorizedGrantTypes().contains("refresh_token");
- }
- return this.supportRefreshToken;
- }
-
- /**
- * An access token enhancer that will be applied to a new token before it is saved in the token store.
- *
- * @param accessTokenEnhancer the access token enhancer to set
- */
- public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
- this.accessTokenEnhancer = accessTokenEnhancer;
- }
-
- /**
- * The validity (in seconds) of the refresh token. If less than or equal to zero then the tokens will be
- * non-expiring.
- *
- * @param refreshTokenValiditySeconds The validity (in seconds) of the refresh token.
- */
- public void setRefreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
- this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
- }
-
- /**
- * The default validity (in seconds) of the access token. Zero or negative for non-expiring tokens. If a client
- * details service is set the validity period will be read from the client, defaulting to this value if not defined
- * by the client.
- *
- * @param accessTokenValiditySeconds The validity (in seconds) of the access token.
- */
- public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {
- this.accessTokenValiditySeconds = accessTokenValiditySeconds;
- }
-
- /**
- * Whether to support the refresh token.
- *
- * @param supportRefreshToken Whether to support the refresh token.
- */
- public void setSupportRefreshToken(boolean supportRefreshToken) {
- this.supportRefreshToken = supportRefreshToken;
- }
-
- /**
- * Whether to reuse refresh tokens (until expired).
- *
- * @param reuseRefreshToken Whether to reuse refresh tokens (until expired).
- */
- public void setReuseRefreshToken(boolean reuseRefreshToken) {
- this.reuseRefreshToken = reuseRefreshToken;
- }
-
- /**
- * The persistence strategy for token storage.
- *
- * @param tokenStore the store for access and refresh tokens.
- */
- public void setTokenStore(TokenStore tokenStore) {
- this.tokenStore = tokenStore;
- }
-
- /**
- * An authentication manager that will be used (if provided) to check the user authentication when a token is
- * refreshed.
- *
- * @param authenticationManager the authenticationManager to set
- */
- public void setAuthenticationManager(AuthenticationManager authenticationManager) {
- this.authenticationManager = authenticationManager;
- }
-
- /**
- * The client details service to use for looking up clients (if necessary). Optional if the access token expiry is
- * set globally via {@link #setAccessTokenValiditySeconds(int)}.
- *
- * @param clientDetailsService the client details service
- */
- public void setClientDetailsService(ClientDetailsService clientDetailsService) {
- this.clientDetailsService = clientDetailsService;
- }
-
-}
diff --git a/yami-shop-security/src/main/resources/mapper/AppConnectMapper.xml b/yami-shop-security/src/main/resources/mapper/AppConnectMapper.xml
deleted file mode 100644
index c650a8b..0000000
--- a/yami-shop-security/src/main/resources/mapper/AppConnectMapper.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/yami-shop-security/yami-shop-security-admin/pom.xml b/yami-shop-security/yami-shop-security-admin/pom.xml
new file mode 100644
index 0000000..2efe489
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-admin/pom.xml
@@ -0,0 +1,24 @@
+
+
+
+ com.yami.shop
+ yami-shop-security
+ 0.0.1-SNAPSHOT
+
+
+ yami-shop-security-admin
+ 4.0.0
+
+ 商城安全模块后台管理部分
+
+
+
+ com.yami.shop
+ yami-shop-security-common
+ ${yami.shop.version}
+
+
+
+
\ No newline at end of file
diff --git a/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/adapter/ResourceServerAdapter.java b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/adapter/ResourceServerAdapter.java
new file mode 100644
index 0000000..ad8f519
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/adapter/ResourceServerAdapter.java
@@ -0,0 +1,29 @@
+package com.yami.shop.security.admin.adapter;
+
+import com.yami.shop.security.common.adapter.DefaultAuthConfigAdapter;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/28 14:57
+ */
+@Component
+public class ResourceServerAdapter extends DefaultAuthConfigAdapter {
+ public static final List EXCLUDE_PATH = Arrays.asList(
+ "/webjars/**",
+ "/swagger/**",
+ "/v2/api-docs",
+ "/doc.html",
+ "/swagger-ui.html",
+ "/swagger-resources/**",
+ "/captcha/**",
+ "/adminLogin");
+
+ @Override
+ public List excludePathPatterns() {
+ return EXCLUDE_PATH;
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/dto/CaptchaAuthenticationDTO.java b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/dto/CaptchaAuthenticationDTO.java
new file mode 100644
index 0000000..82d41a0
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/dto/CaptchaAuthenticationDTO.java
@@ -0,0 +1,17 @@
+package com.yami.shop.security.admin.dto;
+
+import com.yami.shop.security.common.dto.AuthenticationDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 验证码登录
+ * @author 菠萝凤梨
+ * @date 2022/3/28 14:57
+ */
+@Data
+public class CaptchaAuthenticationDTO extends AuthenticationDTO {
+
+ @ApiModelProperty(value = "验证码", required = true)
+ private String captchaVerification;
+}
diff --git a/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/model/YamiSysUser.java b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/model/YamiSysUser.java
new file mode 100644
index 0000000..24c1821
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/model/YamiSysUser.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.admin.model;
+
+import lombok.Data;
+
+import java.util.Set;
+
+/**
+ * 用户详细信息
+ *
+ * @author
+ */
+@Data
+public class YamiSysUser {
+
+ /**
+ * 用户ID
+ */
+ private Long userId;
+
+ private boolean enabled;
+
+ private Set authorities;
+
+ private String username;
+
+ private Long shopId;
+}
diff --git a/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/util/SecurityUtils.java b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/util/SecurityUtils.java
new file mode 100644
index 0000000..76916d7
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-admin/src/main/java/com/yami/shop/security/admin/util/SecurityUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.admin.util;
+
+import com.yami.shop.security.admin.model.YamiSysUser;
+import com.yami.shop.security.common.bo.UserInfoInTokenBO;
+import com.yami.shop.security.common.util.AuthUserContext;
+import lombok.experimental.UtilityClass;
+
+/**
+ *
+ * @author LGH
+ */
+@UtilityClass
+public class SecurityUtils {
+ /**
+ * 获取用户
+ */
+ public YamiSysUser getSysUser() {
+ UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
+
+ YamiSysUser details = new YamiSysUser();
+ details.setUserId(Long.valueOf(userInfoInTokenBO.getUserId()));
+ details.setEnabled(userInfoInTokenBO.getEnabled());
+ details.setUsername(userInfoInTokenBO.getNickName());
+ details.setAuthorities(userInfoInTokenBO.getPerms());
+ details.setShopId(userInfoInTokenBO.getShopId());
+ return details;
+ }
+}
+
diff --git a/yami-shop-security/yami-shop-security-api/pom.xml b/yami-shop-security/yami-shop-security-api/pom.xml
new file mode 100644
index 0000000..081f370
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-api/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ yami-shop-security
+ com.yami.shop
+ 0.0.1-SNAPSHOT
+
+ 4.0.0
+
+ yami-shop-security-api
+ 商城安全模块接口部分
+
+
+
+ com.yami.shop
+ yami-shop-security-common
+ ${yami.shop.version}
+
+
+
+
\ No newline at end of file
diff --git a/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/adapter/ResourceServerAdapter.java b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/adapter/ResourceServerAdapter.java
new file mode 100644
index 0000000..5d5bb51
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/adapter/ResourceServerAdapter.java
@@ -0,0 +1,20 @@
+package com.yami.shop.security.api.adapter;
+
+import com.yami.shop.security.common.adapter.DefaultAuthConfigAdapter;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/28 15:17
+ */
+@Component
+public class ResourceServerAdapter extends DefaultAuthConfigAdapter {
+
+ @Override
+ public List pathPatterns() {
+ return Collections.singletonList("/p/*");
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/controller/LoginController.java b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/controller/LoginController.java
new file mode 100644
index 0000000..d2b49a7
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/controller/LoginController.java
@@ -0,0 +1,80 @@
+package com.yami.shop.security.api.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.yami.shop.bean.model.User;
+import com.yami.shop.common.exception.YamiShopBindException;
+import com.yami.shop.common.util.PrincipalUtil;
+import com.yami.shop.dao.UserMapper;
+import com.yami.shop.security.common.bo.UserInfoInTokenBO;
+import com.yami.shop.security.common.dto.AuthenticationDTO;
+import com.yami.shop.security.common.enums.SysTypeEnum;
+import com.yami.shop.security.common.manager.PasswordCheckManager;
+import com.yami.shop.security.common.manager.PasswordManager;
+import com.yami.shop.security.common.manager.TokenStore;
+import com.yami.shop.security.common.vo.TokenInfoVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/28 15:20
+ */
+@RestController
+@Api(tags = "登录")
+public class LoginController {
+ @Autowired
+ private TokenStore tokenStore;
+
+ @Autowired
+ private UserMapper userMapper;
+
+ @Autowired
+ private PasswordCheckManager passwordCheckManager;
+
+ @Autowired
+ private PasswordManager passwordManager;
+
+ @PostMapping("/login")
+ @ApiOperation(value = "账号密码(用于前端登录)", notes = "通过账号/手机号/用户名密码登录,还要携带用户的类型,也就是用户所在的系统")
+ public ResponseEntity login(
+ @Valid @RequestBody AuthenticationDTO authenticationDTO) {
+ String mobileOrUserName = authenticationDTO.getUserName();
+ User user = getUser(mobileOrUserName);
+
+ String decryptPassword = passwordManager.decryptPassword(authenticationDTO.getPassWord());
+
+ // 半小时内密码输入错误十次,已限制登录30分钟
+ passwordCheckManager.checkPassword(SysTypeEnum.ORDINARY,authenticationDTO.getUserName(), decryptPassword, user.getLoginPassword());
+
+ UserInfoInTokenBO userInfoInToken = new UserInfoInTokenBO();
+ userInfoInToken.setUserId(user.getUserId());
+ userInfoInToken.setSysType(SysTypeEnum.ORDINARY.value());
+ userInfoInToken.setEnabled(user.getStatus() == 1);
+ // 存储token返回vo
+ TokenInfoVO tokenInfoVO = tokenStore.storeAndGetVo(userInfoInToken);
+ return ResponseEntity.ok(tokenInfoVO);
+ }
+
+ private User getUser(String mobileOrUserName) {
+ User user = null;
+ // 手机验证码登陆,或传过来的账号很像手机号
+ if (PrincipalUtil.isMobile(mobileOrUserName)) {
+ user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getUserMobile, mobileOrUserName));
+ }
+ // 如果不是手机验证码登陆, 找不到手机号就找用户名
+ if (user == null) {
+ user = userMapper.selectOneByUserName(mobileOrUserName);
+ }
+ if (user == null) {
+ throw new YamiShopBindException("账号或密码不正确");
+ }
+ return user;
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/model/YamiUser.java b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/model/YamiUser.java
new file mode 100644
index 0000000..ac39c8b
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/model/YamiUser.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.api.model;
+
+import lombok.Data;
+
+/**
+ * 用户详细信息
+ * @author LGH
+ */
+@Data
+public class YamiUser {
+
+ /**
+ * 用户ID
+ */
+ private String userId;
+
+ private String bizUserId;
+
+ private Boolean enabled;
+
+ /**
+ * 自提点Id
+ */
+ private Long stationId;
+
+ /**
+ * 店铺Id
+ */
+ private Long shopId;
+}
diff --git a/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/util/SecurityUtils.java b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/util/SecurityUtils.java
new file mode 100644
index 0000000..d015960
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-api/src/main/java/com/yami/shop/security/api/util/SecurityUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.api.util;
+
+import com.yami.shop.common.util.HttpContextUtils;
+import com.yami.shop.security.api.model.YamiUser;
+import com.yami.shop.security.common.bo.UserInfoInTokenBO;
+import com.yami.shop.security.common.util.AuthUserContext;
+import lombok.experimental.UtilityClass;
+
+/**
+ * @author LGH
+ */
+@UtilityClass
+public class SecurityUtils {
+
+ private static final String USER_REQUEST = "/p/";
+
+ /**
+ * 获取用户
+ */
+ public YamiUser getUser() {
+ if (!HttpContextUtils.getHttpServletRequest().getRequestURI().startsWith(USER_REQUEST)) {
+ // 用户相关的请求,应该以/p开头!!!
+ throw new RuntimeException("yami.user.request.error");
+ }
+ UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
+
+ YamiUser yamiUser = new YamiUser();
+ yamiUser.setUserId(userInfoInTokenBO.getUserId());
+ yamiUser.setBizUserId(userInfoInTokenBO.getBizUserId());
+ yamiUser.setEnabled(userInfoInTokenBO.getEnabled());
+ yamiUser.setShopId(userInfoInTokenBO.getShopId());
+ yamiUser.setStationId(userInfoInTokenBO.getOtherId());
+ return yamiUser;
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/pom.xml b/yami-shop-security/yami-shop-security-common/pom.xml
new file mode 100644
index 0000000..ebbe526
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ com.yami.shop
+ yami-shop-security
+ 0.0.1-SNAPSHOT
+
+
+ 4.0.0
+
+ yami-shop-security-common
+
+
+
+ com.yami.shop
+ yami-shop-service
+ ${yami.shop.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ com.anji-plus
+ captcha
+ 1.3.0
+
+
+
+
\ No newline at end of file
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/AuthConfigAdapter.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/AuthConfigAdapter.java
new file mode 100644
index 0000000..3ee2153
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/AuthConfigAdapter.java
@@ -0,0 +1,27 @@
+package com.yami.shop.security.common.adapter;
+
+import java.util.List;
+
+/**
+ * 实现该接口之后,修改需要授权登陆的路径,不需要授权登陆的路径
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:31
+ */
+public interface AuthConfigAdapter {
+ /**
+ * 也许需要登录才可用的url
+ */
+ String MAYBE_AUTH_URI = "/**/ma/**";
+
+ /**
+ * 需要授权登陆的路径
+ * @return 需要授权登陆的路径列表
+ */
+ List pathPatterns();
+
+ /**
+ * 不需要授权登陆的路径
+ * @return 不需要授权登陆的路径列表
+ */
+ List excludePathPatterns();
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/CaptchaCacheServiceRedisImpl.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/CaptchaCacheServiceRedisImpl.java
new file mode 100644
index 0000000..748ec0d
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/CaptchaCacheServiceRedisImpl.java
@@ -0,0 +1,36 @@
+package com.yami.shop.security.common.adapter;
+
+import com.anji.captcha.service.CaptchaCacheService;
+import com.yami.shop.common.util.RedisUtil;
+
+/**
+ * 适配验证码在redis的存储
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+public class CaptchaCacheServiceRedisImpl implements CaptchaCacheService {
+ @Override
+ public void set(String key, String value, long expiresInSeconds) {
+ RedisUtil.set(key, value, expiresInSeconds);
+ }
+
+ @Override
+ public boolean exists(String key) {
+ return RedisUtil.hasKey(key);
+ }
+
+ @Override
+ public void delete(String key) {
+ RedisUtil.del(key);
+ }
+
+ @Override
+ public String get(String key) {
+ return RedisUtil.get(key);
+ }
+
+ @Override
+ public String type() {
+ return "redis";
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/DefaultAuthConfigAdapter.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/DefaultAuthConfigAdapter.java
new file mode 100644
index 0000000..e5c35f5
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/DefaultAuthConfigAdapter.java
@@ -0,0 +1,29 @@
+package com.yami.shop.security.common.adapter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+public class DefaultAuthConfigAdapter implements AuthConfigAdapter {
+ private static final Logger logger = LoggerFactory.getLogger(DefaultAuthConfigAdapter.class);
+
+ public DefaultAuthConfigAdapter() {
+ logger.info("not implement other AuthConfigAdapter, use DefaultAuthConfigAdapter... all url need auth...");
+ }
+
+ @Override
+ public List pathPatterns() {
+ return Collections.singletonList("/*");
+ }
+
+ @Override
+ public List excludePathPatterns() {
+ return Collections.emptyList();
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/MallWebSecurityConfigurerAdapter.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/MallWebSecurityConfigurerAdapter.java
new file mode 100644
index 0000000..ed289d4
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/adapter/MallWebSecurityConfigurerAdapter.java
@@ -0,0 +1,25 @@
+package com.yami.shop.security.common.adapter;
+
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.stereotype.Component;
+import org.springframework.web.cors.CorsUtils;
+
+/**
+ * 使用security的防火墙功能,但不使用security的认证授权登录
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Component
+public class MallWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable().cors() // We don't need CSRF for token based authentication
+ .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
+ .and()
+ .authorizeRequests().antMatchers(
+ "/**").permitAll();
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/bo/TokenInfoBO.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/bo/TokenInfoBO.java
new file mode 100644
index 0000000..0219166
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/bo/TokenInfoBO.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.bo;
+
+
+import lombok.Data;
+
+/**
+ * token信息,该信息存在redis中
+ *
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Data
+public class TokenInfoBO {
+
+ /**
+ * 保存在token信息里面的用户信息
+ */
+ private UserInfoInTokenBO userInfoInToken;
+
+ private String accessToken;
+
+ private String refreshToken;
+
+ /**
+ * 在多少秒后过期
+ */
+ private Integer expiresIn;
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/bo/UserInfoInTokenBO.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/bo/UserInfoInTokenBO.java
new file mode 100644
index 0000000..8b74ed5
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/bo/UserInfoInTokenBO.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.bo;
+
+import lombok.Data;
+
+import java.util.Set;
+
+/**
+ * 保存在token信息里面的用户信息
+ *
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Data
+public class UserInfoInTokenBO {
+
+ /**
+ * 用户在自己系统的用户id
+ */
+ private String userId;
+
+ /**
+ * 租户id (商家id)
+ */
+ private Long shopId;
+
+ /**
+ * 昵称
+ */
+ private String nickName;
+
+ /**
+ * 系统类型
+ * @see com.yami.shop.security.common.enums.SysTypeEnum
+ */
+ private Integer sysType;
+
+ /**
+ * 是否是管理员
+ */
+ private Integer isAdmin;
+
+ private String bizUserId;
+
+ /**
+ * 权限列表
+ */
+ private Set perms;
+
+ /**
+ * 状态 1 正常 0 无效
+ */
+ private Boolean enabled;
+
+ /**
+ * 其他Id
+ */
+ private Long otherId;
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/AuthConfig.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/AuthConfig.java
new file mode 100644
index 0000000..e841b12
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/AuthConfig.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.config;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.yami.shop.security.common.adapter.AuthConfigAdapter;
+import com.yami.shop.security.common.adapter.DefaultAuthConfigAdapter;
+import com.yami.shop.security.common.filter.AuthFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+
+import javax.servlet.DispatcherType;
+
+/**
+ * 授权配置
+ *
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled=true)
+public class AuthConfig {
+
+ @Autowired
+ private AuthFilter authFilter;
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AuthConfigAdapter authConfigAdapter() {
+ return new DefaultAuthConfigAdapter();
+ }
+
+
+ @Bean
+ @Lazy
+ public FilterRegistrationBean filterRegistration(AuthConfigAdapter authConfigAdapter) {
+ FilterRegistrationBean registration = new FilterRegistrationBean<>();
+ // 添加过滤器
+ registration.setFilter(authFilter);
+ // 设置过滤路径,/*所有路径
+ registration.addUrlPatterns(ArrayUtil.toArray(authConfigAdapter.pathPatterns(), String.class));
+ registration.setName("authFilter");
+ // 设置优先级
+ registration.setOrder(0);
+ registration.setDispatcherTypes(DispatcherType.REQUEST);
+ return registration;
+ }
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/CaptchaConfig.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/CaptchaConfig.java
new file mode 100644
index 0000000..a9aa3df
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/CaptchaConfig.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.config;
+
+import com.anji.captcha.model.common.CaptchaTypeEnum;
+import com.anji.captcha.model.common.Const;
+import com.anji.captcha.service.CaptchaService;
+import com.anji.captcha.service.impl.CaptchaServiceFactory;
+import com.anji.captcha.util.ImageUtils;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.util.Base64Utils;
+import org.springframework.util.FileCopyUtils;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * 这里把验证码的底图存入redis中,如果报获取验证码失败找管理员什么的可以看下redis的情况
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Configuration
+public class CaptchaConfig {
+
+ @Bean
+ public CaptchaService captchaService() {
+ Properties config = new Properties();
+ config.put(Const.CAPTCHA_CACHETYPE, "redis");
+ config.put(Const.CAPTCHA_WATER_MARK, "");
+ // 滑动验证
+ config.put(Const.CAPTCHA_TYPE, CaptchaTypeEnum.BLOCKPUZZLE.getCodeValue());
+ config.put(Const.CAPTCHA_INIT_ORIGINAL, "true");
+ initializeBaseMap();
+ return CaptchaServiceFactory.getInstance(config);
+ }
+
+ private static void initializeBaseMap() {
+ ImageUtils.cacheBootImage(getResourcesImagesFile("classpath:captcha" + "/original/*.png"), getResourcesImagesFile("classpath:captcha" + "/slidingBlock/*.png"), Collections.emptyMap());
+ }
+
+ public static Map getResourcesImagesFile(String path) {
+ Map imgMap = new HashMap<>(16);
+ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+
+ try {
+ Resource[] resources = resolver.getResources(path);
+ Resource[] var4 = resources;
+ int var5 = resources.length;
+
+ for(int var6 = 0; var6 < var5; ++var6) {
+ Resource resource = var4[var6];
+ byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
+ String string = Base64Utils.encodeToString(bytes);
+ String filename = resource.getFilename();
+ imgMap.put(filename, string);
+ }
+ } catch (Exception var11) {
+ var11.printStackTrace();
+ }
+
+ return imgMap;
+ }
+
+}
diff --git a/yami-shop-security/src/main/java/com/yami/shop/security/config/CorsConfig.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/CorsConfig.java
similarity index 96%
rename from yami-shop-security/src/main/java/com/yami/shop/security/config/CorsConfig.java
rename to yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/CorsConfig.java
index 0534790..890272a 100644
--- a/yami-shop-security/src/main/java/com/yami/shop/security/config/CorsConfig.java
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/CorsConfig.java
@@ -1,4 +1,4 @@
-package com.yami.shop.security.config;
+package com.yami.shop.security.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
diff --git a/yami-shop-security/src/main/java/com/yami/shop/security/config/WebSecurityConfig.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/PasswordConfig.java
similarity index 53%
rename from yami-shop-security/src/main/java/com/yami/shop/security/config/WebSecurityConfig.java
rename to yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/PasswordConfig.java
index 93f35ec..e09ec7a 100644
--- a/yami-shop-security/src/main/java/com/yami/shop/security/config/WebSecurityConfig.java
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/config/PasswordConfig.java
@@ -7,37 +7,22 @@
*
* 版权所有,侵权必究!
*/
+package com.yami.shop.security.common.config;
-package com.yami.shop.security.config;
-
-
-import lombok.SneakyThrows;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
-
/**
- * @author LGH
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
*/
@Configuration
-@Order(90)
-public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Override
- @Bean
- @SneakyThrows
- public AuthenticationManager authenticationManagerBean() {
- return super.authenticationManagerBean();
- }
+public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
-
}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/CaptchaController.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/CaptchaController.java
new file mode 100644
index 0000000..eee5070
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/CaptchaController.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.controller;
+
+import com.anji.captcha.model.common.RepCodeEnum;
+import com.anji.captcha.model.common.ResponseModel;
+import com.anji.captcha.model.vo.CaptchaVO;
+import com.anji.captcha.service.CaptchaService;
+import io.swagger.annotations.Api;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@RestController
+@RequestMapping("/captcha")
+@Api(tags = "验证码")
+public class CaptchaController {
+
+ private final CaptchaService captchaService;
+
+ public CaptchaController(CaptchaService captchaService) {
+ this.captchaService = captchaService;
+ }
+
+ @PostMapping({ "/get" })
+ public ResponseEntity get(@RequestBody CaptchaVO captchaVO) {
+ return ResponseEntity.ok(captchaService.get(captchaVO));
+ }
+
+ @PostMapping({ "/check" })
+ public ResponseEntity check(@RequestBody CaptchaVO captchaVO) {
+ ResponseModel responseModel;
+ try {
+ responseModel = captchaService.check(captchaVO);
+ }catch (Exception e) {
+ return ResponseEntity.ok(ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_COORDINATE_ERROR));
+ }
+ return ResponseEntity.ok(responseModel);
+ }
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/LogoutController.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/LogoutController.java
new file mode 100644
index 0000000..88510ce
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/LogoutController.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.yami.shop.security.common.manager.TokenStore;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@RestController
+@Api(tags = "注销")
+public class LogoutController {
+
+ @Autowired
+ private TokenStore tokenStore;
+
+ @PostMapping("/logOut")
+ @ApiOperation(value = "退出登陆", notes = "点击退出登陆,清除token,清除菜单缓存")
+ public ResponseEntity logOut(HttpServletRequest request) {
+ String accessToken = request.getHeader("Authorization");
+ if (StrUtil.isBlank(accessToken)) {
+ return ResponseEntity.ok().build();
+ }
+ // 删除该用户在该系统当前的token
+ tokenStore.deleteCurrentToken(accessToken);
+ return ResponseEntity.ok().build();
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/TokenController.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/TokenController.java
new file mode 100644
index 0000000..acb1528
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/controller/TokenController.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.controller;
+
+import com.yami.shop.security.common.bo.TokenInfoBO;
+import com.yami.shop.security.common.dto.RefreshTokenDTO;
+import com.yami.shop.security.common.manager.TokenStore;
+import com.yami.shop.security.common.vo.TokenInfoVO;
+import io.swagger.annotations.Api;
+import ma.glasnost.orika.MapperFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@RestController
+@Api(tags = "token")
+public class TokenController {
+
+ @Autowired
+ private TokenStore tokenStore;
+
+ @Autowired
+ private MapperFacade mapperFacade;
+
+ @PostMapping("/token/refresh")
+ public ResponseEntity refreshToken(@Valid @RequestBody RefreshTokenDTO refreshTokenDTO) {
+ TokenInfoBO tokenInfoServerResponseEntity = tokenStore
+ .refreshToken(refreshTokenDTO.getRefreshToken());
+ return ResponseEntity
+ .ok(mapperFacade.map(tokenInfoServerResponseEntity, TokenInfoVO.class));
+ }
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/dto/AuthenticationDTO.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/dto/AuthenticationDTO.java
new file mode 100644
index 0000000..d58040c
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/dto/AuthenticationDTO.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 用于登陆传递账号密码
+ *
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Data
+public class AuthenticationDTO {
+
+ /**
+ * 用户名
+ */
+ @NotBlank(message = "userName不能为空")
+ @ApiModelProperty(value = "用户名/邮箱/手机号", required = true)
+ protected String userName;
+
+ /**
+ * 密码
+ */
+ @NotBlank(message = "passWord不能为空")
+ @ApiModelProperty(value = "一般用作密码", required = true)
+ protected String passWord;
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/dto/RefreshTokenDTO.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/dto/RefreshTokenDTO.java
new file mode 100644
index 0000000..57b6b9d
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/dto/RefreshTokenDTO.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 刷新token
+ *
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+public class RefreshTokenDTO {
+
+ /**
+ * refreshToken
+ */
+ @NotBlank(message = "refreshToken不能为空")
+ @ApiModelProperty(value = "refreshToken", required = true)
+ private String refreshToken;
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public void setRefreshToken(String refreshToken) {
+ this.refreshToken = refreshToken;
+ }
+
+ @Override
+ public String toString() {
+ return "RefreshTokenDTO{" + "refreshToken='" + refreshToken + '\'' + '}';
+ }
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/enums/SysTypeEnum.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/enums/SysTypeEnum.java
new file mode 100644
index 0000000..8622a8d
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/enums/SysTypeEnum.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.enums;
+
+/**
+ * 系统类型
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+public enum SysTypeEnum {
+
+ /**
+ * 普通用户系统
+ */
+ ORDINARY(0),
+
+ /**
+ * 后台
+ */
+ ADMIN(1),
+ ;
+
+ private final Integer value;
+
+ public Integer value() {
+ return value;
+ }
+
+ SysTypeEnum(Integer value) {
+ this.value = value;
+ }
+
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/filter/AuthFilter.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/filter/AuthFilter.java
new file mode 100644
index 0000000..6f71748
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/filter/AuthFilter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.filter;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yami.shop.common.exception.YamiShopBindException;
+import com.yami.shop.common.handler.HttpHandler;
+import com.yami.shop.security.common.adapter.AuthConfigAdapter;
+import com.yami.shop.security.common.bo.UserInfoInTokenBO;
+import com.yami.shop.security.common.manager.TokenStore;
+import com.yami.shop.security.common.util.AuthUserContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.util.AntPathMatcher;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 授权过滤,只要实现AuthConfigAdapter接口,添加对应路径即可:
+ *
+ * @author 菠萝凤梨
+ * @date 2022/3/25 17:33
+ */
+@Component
+public class AuthFilter implements Filter {
+
+ private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
+
+ @Autowired
+ private AuthConfigAdapter authConfigAdapter;
+
+ @Autowired
+ private HttpHandler httpHandler;
+
+ @Autowired
+ private TokenStore tokenStore;
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse resp = (HttpServletResponse) response;
+
+ String requestUri = req.getRequestURI();
+
+ List excludePathPatterns = authConfigAdapter.excludePathPatterns();
+
+ AntPathMatcher pathMatcher = new AntPathMatcher();
+ // 如果匹配不需要授权的路径,就不需要校验是否需要授权
+ if (CollectionUtil.isNotEmpty(excludePathPatterns)) {
+ for (String excludePathPattern : excludePathPatterns) {
+ if (pathMatcher.match(excludePathPattern, requestUri)) {
+ chain.doFilter(req, resp);
+ return;
+ }
+ }
+ }
+
+ String accessToken = req.getHeader("Authorization");
+ // 也许需要登录,不登陆也能用的uri
+ boolean mayAuth = pathMatcher.match(AuthConfigAdapter.MAYBE_AUTH_URI, requestUri);
+
+
+ UserInfoInTokenBO userInfoInToken = null;
+
+ try {
+ // 如果有token,就要获取token
+ if (StrUtil.isNotBlank(accessToken)) {
+ userInfoInToken = tokenStore.getUserInfoByAccessToken(accessToken, true);
+ }
+ else if (!mayAuth) {
+ // 返回前端401
+ httpHandler.printServerResponseToWeb(HttpStatus.UNAUTHORIZED.getReasonPhrase(), HttpStatus.UNAUTHORIZED.value());
+ return;
+ }
+ // 保存上下文
+ AuthUserContext.set(userInfoInToken);
+
+ chain.doFilter(req, resp);
+
+ }catch (Exception e) {
+ // 手动捕获下非controller异常
+ if (e instanceof YamiShopBindException) {
+ httpHandler.printServerResponseToWeb(e.getMessage(), ((YamiShopBindException) e).getHttpStatusCode());
+ } else {
+ throw e;
+ }
+ } finally {
+ AuthUserContext.clean();
+ }
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordCheckManager.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordCheckManager.java
new file mode 100644
index 0000000..ff35036
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordCheckManager.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.manager;
+
+import cn.hutool.core.util.StrUtil;
+import com.yami.shop.common.exception.YamiShopBindException;
+import com.yami.shop.common.util.IPHelper;
+import com.yami.shop.common.util.RedisUtil;
+import com.yami.shop.security.common.enums.SysTypeEnum;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+/**
+ * @date 2022/3/25 17:33
+ * @author lh
+ */
+@Component
+public class PasswordCheckManager {
+
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ /**
+ * 半小时内最多错误10次
+ */
+ private static final int TIMES_CHECK_INPUT_PASSWORD_NUM = 10;
+
+ /**
+ * 检查用户输入错误的验证码次数
+ */
+ private static final String CHECK_VALID_CODE_NUM_PREFIX = "checkUserInputErrorPassword_";
+ public void checkPassword(SysTypeEnum sysTypeEnum,String userNameOrMobile, String rawPassword, String encodedPassword) {
+
+ String checkPrefix = sysTypeEnum.value() + CHECK_VALID_CODE_NUM_PREFIX + IPHelper.getIpAddr();
+
+ int count = 0;
+ if(RedisUtil.hasKey(checkPrefix + userNameOrMobile)){
+ count = RedisUtil.get(checkPrefix + userNameOrMobile);
+ }
+ if(count > TIMES_CHECK_INPUT_PASSWORD_NUM){
+ throw new YamiShopBindException("半小时内密码输入错误十次,已限制登录30分钟");
+ }
+ // 半小时后失效
+ RedisUtil.set(checkPrefix + userNameOrMobile,count,1800);
+ // 密码不正确
+ if (StrUtil.isBlank(encodedPassword) || !passwordEncoder.matches(rawPassword,encodedPassword)){
+ count++;
+ // 半小时后失效
+ RedisUtil.set(checkPrefix + userNameOrMobile,count,1800);
+ throw new YamiShopBindException("账号或密码不正确");
+ }
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordManager.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordManager.java
new file mode 100644
index 0000000..e73f98e
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/PasswordManager.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.manager;
+
+import cn.hutool.crypto.symmetric.AES;
+import com.yami.shop.common.exception.YamiShopBindException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author 菠萝凤梨
+ * @date 2022/1/19 16:02
+ */
+@Component
+public class PasswordManager {
+ private static final Logger logger = LoggerFactory.getLogger(PasswordManager.class);
+
+ /**
+ * 用于aes签名的key,16位
+ */
+ @Value("${auth.password.signKey:-mall4j-password}")
+ public String passwordSignKey;
+
+ public String decryptPassword(String data) {
+ AES aes = new AES(passwordSignKey.getBytes(StandardCharsets.UTF_8));
+ String decryptStr;
+ String decryptPassword;
+ try {
+ decryptStr = aes.decryptStr(data);
+ decryptPassword = decryptStr.substring(13);
+ } catch (Exception e) {
+ logger.error("Exception:", e);
+ throw new YamiShopBindException("AES解密错误", e);
+ }
+ return decryptPassword;
+ }
+}
diff --git a/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/TokenStore.java b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/TokenStore.java
new file mode 100644
index 0000000..1379e58
--- /dev/null
+++ b/yami-shop-security/yami-shop-security-common/src/main/java/com/yami/shop/security/common/manager/TokenStore.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
+ *
+ * https://www.mall4j.com/
+ *
+ * 未经允许,不可做商业用途!
+ *
+ * 版权所有,侵权必究!
+ */
+package com.yami.shop.security.common.manager;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.symmetric.AES;
+import com.yami.shop.common.constants.OauthCacheNames;
+import com.yami.shop.common.enums.YamiHttpStatus;
+import com.yami.shop.common.exception.YamiShopBindException;
+import com.yami.shop.common.serializer.redis.KryoRedisSerializer;
+import com.yami.shop.common.util.PrincipalUtil;
+import com.yami.shop.security.common.bo.TokenInfoBO;
+import com.yami.shop.security.common.bo.UserInfoInTokenBO;
+import com.yami.shop.security.common.enums.SysTypeEnum;
+import com.yami.shop.security.common.vo.TokenInfoVO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * token管理 1. 登陆返回token 2. 刷新token 3. 清除用户过去token 4. 校验token
+ *
+ * @author FrozenWatermelon
+ * @date 2020/7/2
+ */
+@Component
+public class TokenStore {
+
+ private static final Logger logger = LoggerFactory.getLogger(TokenStore.class);
+
+ /**
+ * 用于aes签名的key,16位
+ */
+ @Value("${auth.token.signKey:-mall4j--mall4j-}")
+ public String tokenSignKey;
+
+ private final RedisTemplate redisTemplate;
+
+ private final RedisSerializer