parent
de921aceec
commit
b918fad14f
@ -1,31 +0,0 @@
|
||||
package com.yami.shop.admin.security;
|
||||
|
||||
import com.yami.shop.security.service.YamiSysUser;
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* token增强
|
||||
* @author LGH
|
||||
*/
|
||||
@Component
|
||||
public class AdminTokenEnhancer implements TokenEnhancer {
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
final Map<String, Object> additionalInfo = new HashMap<>(8);
|
||||
YamiSysUser yamiSysUser = (YamiSysUser) authentication.getUserAuthentication().getPrincipal();
|
||||
additionalInfo.put("shopId", yamiSysUser.getShopId());
|
||||
additionalInfo.put("userId", yamiSysUser.getUserId());
|
||||
additionalInfo.put("authorities", yamiSysUser.getAuthorities());
|
||||
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package com.yami.shop.api.security;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.emoji.EmojiUtil;
|
||||
import com.yami.shop.security.service.YamiUser;
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* token增强
|
||||
* @author LGH
|
||||
*/
|
||||
@Component
|
||||
public class ApiTokenEnhancer implements TokenEnhancer {
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
Map<String, Object> additionalInfo = new HashMap<>(8);
|
||||
YamiUser yamiUser = (YamiUser) authentication.getUserAuthentication().getPrincipal();
|
||||
additionalInfo.put("userId", yamiUser.getUserId());
|
||||
additionalInfo.put("nickName", EmojiUtil.toUnicode(StrUtil.isBlank(yamiUser.getName())? "" : yamiUser.getName()));
|
||||
additionalInfo.put("pic",yamiUser.getPic());
|
||||
additionalInfo.put("enabled",yamiUser.isEnabled());
|
||||
|
||||
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
@ -1,154 +0,0 @@
|
||||
package com.yami.shop.api.security;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.yami.shop.common.exception.YamiShopBindException;
|
||||
import com.yami.shop.common.util.Json;
|
||||
import com.yami.shop.common.xss.XssUtil;
|
||||
import com.yami.shop.security.exception.BadCredentialsException;
|
||||
import com.yami.shop.security.exception.UsernameNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author SJL
|
||||
*/
|
||||
public class YamiAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
private PasswordEncoder passwordEncoder;
|
||||
/**
|
||||
* 请求字符串的最大长度 1m
|
||||
*/
|
||||
public static final int MAX_STRING_SIZE = 1024 * 1024;
|
||||
|
||||
protected YamiAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
|
||||
super(defaultFilterProcessesUrl);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Autowired
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
super.setAuthenticationManager(authenticationManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Autowired
|
||||
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
|
||||
super.setAuthenticationSuccessHandler(successHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Autowired
|
||||
public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||
super.setAuthenticationFailureHandler(failureHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, ServletException{
|
||||
if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
|
||||
throw new HttpRequestMethodNotSupportedException(request.getMethod(), new String[] { "POST" });
|
||||
}
|
||||
|
||||
AuthenticationToken authenticationToken = Json.parseObject(getStringFromStream(request), AuthenticationToken.class);
|
||||
UserDetails userDetails = getUserDetails(authenticationToken);
|
||||
return handleAuthenticationToken(authenticationToken,userDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param authenticationToken
|
||||
* @return
|
||||
*/
|
||||
protected UserDetails getUserDetails(AuthenticationToken authenticationToken) {
|
||||
UserDetails user;
|
||||
try {
|
||||
user = userDetailsService.loadUserByUsername(authenticationToken.getPrincipal());
|
||||
} catch (UsernameNotFoundException var6) {
|
||||
// 账号或密码不正确
|
||||
throw new UsernameNotFoundException("账号或密码不正确");
|
||||
}
|
||||
if (!user.isEnabled()) {
|
||||
// 账号已被锁定,请联系管理员
|
||||
throw new UsernameNotFoundException("账号已被锁定,请联系管理员");
|
||||
}
|
||||
|
||||
String encodedPassword = user.getPassword();
|
||||
String rawPassword = authenticationToken.getCredentials().toString();
|
||||
|
||||
// 密码不正确
|
||||
if (!passwordEncoder.matches(rawPassword,encodedPassword)){
|
||||
// 账号或密码不正确
|
||||
throw new BadCredentialsException("账号或密码不正确");
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存用户信息
|
||||
*/
|
||||
protected AuthenticationToken handleAuthenticationToken(AuthenticationToken authentication, UserDetails userDetails) {
|
||||
// 保存用户信息
|
||||
authentication.setPrincipal(userDetails.getUsername());
|
||||
authentication.setDetails(userDetails);
|
||||
authentication.setAuthenticated(true);
|
||||
return authentication;
|
||||
}
|
||||
|
||||
|
||||
public String getStringFromStream(HttpServletRequest req) {
|
||||
if (req.getContentLength() > MAX_STRING_SIZE) {
|
||||
// 请求数据过长
|
||||
throw new YamiShopBindException("yami.request.data.too.long");
|
||||
}
|
||||
ServletInputStream is;
|
||||
try {
|
||||
is = req.getInputStream();
|
||||
int nRead = 1;
|
||||
int nTotalRead = 0;
|
||||
byte[] bytes = new byte[1024];
|
||||
while (nRead > 0) {
|
||||
nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
|
||||
if (nRead > 0) {
|
||||
nTotalRead = nTotalRead + nRead;
|
||||
}
|
||||
}
|
||||
if (nTotalRead > MAX_STRING_SIZE) {
|
||||
// 请求数据过长
|
||||
throw new YamiShopBindException("yami.request.data.too.long");
|
||||
}
|
||||
return XssUtil.clean(new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.yami.shop.common.constants;
|
||||
|
||||
/**
|
||||
* @author 菠萝凤梨
|
||||
* @date 2022/3/28 14:32
|
||||
*/
|
||||
public interface OauthCacheNames {
|
||||
|
||||
/**
|
||||
* oauth 授权相关key
|
||||
*/
|
||||
String OAUTH_PREFIX = "mall4j_oauth:";
|
||||
|
||||
/**
|
||||
* token 授权相关key
|
||||
*/
|
||||
String OAUTH_TOKEN_PREFIX = OAUTH_PREFIX + "token:";
|
||||
|
||||
/**
|
||||
* 保存token 缓存使用key
|
||||
*/
|
||||
String ACCESS = OAUTH_TOKEN_PREFIX + "access:";
|
||||
|
||||
/**
|
||||
* 刷新token 缓存使用key
|
||||
*/
|
||||
String REFRESH_TO_ACCESS = OAUTH_TOKEN_PREFIX + "refresh_to_access:";
|
||||
|
||||
/**
|
||||
* 根据uid获取保存的token key缓存使用的key
|
||||
*/
|
||||
String UID_TO_ACCESS = OAUTH_TOKEN_PREFIX + "uid_to_access:";
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.yami.shop.common.handler;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import com.yami.shop.common.exception.YamiShopBindException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* @author 菠萝凤梨
|
||||
* @date 2022/3/28 14:15
|
||||
*/
|
||||
@Component
|
||||
public class HttpHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpHandler.class);
|
||||
|
||||
public <T> void printServerResponseToWeb(String str, int status) {
|
||||
|
||||
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
|
||||
.getRequestAttributes();
|
||||
if (requestAttributes == null) {
|
||||
logger.error("requestAttributes is null, can not print to web");
|
||||
return;
|
||||
}
|
||||
HttpServletResponse response = requestAttributes.getResponse();
|
||||
if (response == null) {
|
||||
logger.error("httpServletResponse is null, can not print to web");
|
||||
return;
|
||||
}
|
||||
logger.error("response error: " + str);
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setStatus(status);
|
||||
PrintWriter printWriter = null;
|
||||
try {
|
||||
printWriter = response.getWriter();
|
||||
printWriter.write(str);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new YamiShopBindException("io 异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>yami-shop</artifactId>
|
||||
<groupId>com.yami.shop</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>yami-shop-mp</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.yami.shop</groupId>
|
||||
<artifactId>yami-shop-security</artifactId>
|
||||
<version>${yami.shop.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -1,72 +0,0 @@
|
||||
package com.yami.shop.mp.component;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.yami.shop.common.exception.YamiShopBindException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* WxMaServiceImpl 在集群模式获取accessToken的方式
|
||||
* @author LGH
|
||||
*/
|
||||
@Slf4j
|
||||
public class WxMaServiceClusterImpl extends WxMaServiceImpl {
|
||||
|
||||
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
|
||||
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
public void setRedissonClient(RedissonClient redissonClient) {
|
||||
this.redissonClient = redissonClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||
if (!this.getWxMaConfig().isAccessTokenExpired() && !forceRefresh) {
|
||||
return this.getWxMaConfig().getAccessToken();
|
||||
}
|
||||
|
||||
RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + ":WxMaServiceCluster:getAccessToken");
|
||||
|
||||
try {
|
||||
boolean lockSuccess;
|
||||
try {
|
||||
lockSuccess = rLock.tryLock(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
return this.getWxMaConfig().getAccessToken();
|
||||
}
|
||||
|
||||
if (!lockSuccess) {
|
||||
throw new YamiShopBindException("服务器繁忙,请稍后再试");
|
||||
}
|
||||
|
||||
if (!this.getWxMaConfig().isAccessTokenExpired()) {
|
||||
return this.getWxMaConfig().getAccessToken();
|
||||
}
|
||||
|
||||
String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(),
|
||||
this.getWxMaConfig().getSecret());
|
||||
String resultContent = HttpUtil.get(url);
|
||||
WxError error = WxError.fromJson(resultContent);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.getWxMaConfig().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
|
||||
return this.getWxMaConfig().getAccessToken();
|
||||
|
||||
} finally {
|
||||
rLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
package com.yami.shop.mp.component;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.yami.shop.common.exception.YamiShopBindException;
|
||||
import me.chanjar.weixin.common.WxType;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
|
||||
|
||||
/**
|
||||
* WxMpServiceImpl 在集群模式获取accessToken的方式
|
||||
* @author LGH
|
||||
*/
|
||||
public class WxMpServiceClusterImpl extends WxMpServiceHttpClientImpl {
|
||||
|
||||
|
||||
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
|
||||
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
public void setRedissonClient(RedissonClient redissonClient) {
|
||||
this.redissonClient = redissonClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||
if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) {
|
||||
return this.getWxMpConfigStorage().getAccessToken();
|
||||
}
|
||||
|
||||
RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + ":WxMpServiceCluster:getAccessToken");
|
||||
|
||||
try {
|
||||
boolean doingUpdateAccessToken;
|
||||
try {
|
||||
doingUpdateAccessToken = rLock.tryLock(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
return this.getWxMpConfigStorage().getAccessToken();
|
||||
}
|
||||
|
||||
if (!doingUpdateAccessToken) {
|
||||
throw new YamiShopBindException("服务器繁忙,请稍后再试");
|
||||
}
|
||||
|
||||
if (!this.getWxMpConfigStorage().isAccessTokenExpired()) {
|
||||
return this.getWxMpConfigStorage().getAccessToken();
|
||||
}
|
||||
String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret());
|
||||
String resultContent = HttpUtil.get(url);
|
||||
|
||||
WxError error = WxError.fromJson(resultContent, WxType.MP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
return this.getWxMpConfigStorage().getAccessToken();
|
||||
|
||||
} finally {
|
||||
rLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
ma.appid=
|
||||
ma.secret=
|
||||
@ -1,4 +0,0 @@
|
||||
mp.appid=
|
||||
mp.secret=
|
||||
mp.token=
|
||||
mp.aesKey=
|
||||
@ -1,3 +0,0 @@
|
||||
pay.mchId=
|
||||
pay.mchKey=
|
||||
pay.keyPath=classpath:xxx.p12
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue