Commit 6a1ec9f7 by 罗长华

完成api签名认证服务端处理逻辑

parent e37a2d41
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package io.geekidea.springbootplus.config; package io.geekidea.springbootplus.config;
import com.alibaba.fastjson.JSON;
import io.geekidea.springbootplus.config.properties.JwtProperties; import io.geekidea.springbootplus.config.properties.JwtProperties;
import io.geekidea.springbootplus.config.properties.ShiroPermissionProperties; import io.geekidea.springbootplus.config.properties.ShiroPermissionProperties;
import io.geekidea.springbootplus.config.properties.ShiroProperties; import io.geekidea.springbootplus.config.properties.ShiroProperties;
...@@ -26,8 +25,21 @@ import io.geekidea.springbootplus.framework.shiro.jwt.JwtCredentialsMatcher; ...@@ -26,8 +25,21 @@ import io.geekidea.springbootplus.framework.shiro.jwt.JwtCredentialsMatcher;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtFilter; import io.geekidea.springbootplus.framework.shiro.jwt.JwtFilter;
import io.geekidea.springbootplus.framework.shiro.jwt.realm.JwtRealmAppUser; import io.geekidea.springbootplus.framework.shiro.jwt.realm.JwtRealmAppUser;
import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService; import io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService;
import io.geekidea.springbootplus.framework.shiro.signature.ApplicationService;
import io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthFilter;
import io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthRealm;
import io.geekidea.springbootplus.framework.util.IniUtil; import io.geekidea.springbootplus.framework.util.IniUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
...@@ -54,13 +66,7 @@ import org.springframework.context.annotation.Bean; ...@@ -54,13 +66,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.DispatcherType; import com.alibaba.fastjson.JSON;
import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** /**
* Shiro配置 * Shiro配置
...@@ -114,6 +120,18 @@ public class ShiroConfig { ...@@ -114,6 +120,18 @@ public class ShiroConfig {
return jwtRealm; return jwtRealm;
} }
/**
* 用户客户端Realm
* @Author luozh
* @Date 2022年04月15日 05:27:00
* @param
* @Return
*/
public SignatureAuthRealm signatureAuthRealm() {
SignatureAuthRealm realm = new SignatureAuthRealm();
return realm;
}
/** /**
* subject不存储到Session中 * subject不存储到Session中
...@@ -148,6 +166,7 @@ public class ShiroConfig { ...@@ -148,6 +166,7 @@ public class ShiroConfig {
List<Realm> realms = new ArrayList<>(); List<Realm> realms = new ArrayList<>();
// realms.add(jwtRealmSystem(sysLoginRedisService)); // realms.add(jwtRealmSystem(sysLoginRedisService));
realms.add(jwtRealmAppUser(appLoginRedisService)); realms.add(jwtRealmAppUser(appLoginRedisService));
realms.add(signatureAuthRealm());
// realms.add(jwtRealmMerchant(merchantLoginRedisService)); // realms.add(jwtRealmMerchant(merchantLoginRedisService));
// 用户数据连接器 // 用户数据连接器
...@@ -171,13 +190,15 @@ public class ShiroConfig { ...@@ -171,13 +190,15 @@ public class ShiroConfig {
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager, public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
ShiroLoginService shiroLoginService, ShiroLoginService shiroLoginService,
ShiroProperties shiroProperties, ShiroProperties shiroProperties,
JwtProperties jwtProperties) { JwtProperties jwtProperties,
ApplicationService applicationService
) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器 // 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置过滤器 // 设置过滤器
Map<String, Filter> filterMap = getFilterMap(shiroLoginService); Map<String, Filter> filterMap = getFilterMap(shiroLoginService, applicationService);
shiroFilterFactoryBean.setFilters(filterMap); shiroFilterFactoryBean.setFilters(filterMap);
// 设置过滤器顺序 // 设置过滤器顺序
Map<String, String> filterChainMap = getFilterChainDefinitionMap(shiroProperties); Map<String, String> filterChainMap = getFilterChainDefinitionMap(shiroProperties);
...@@ -191,9 +212,10 @@ public class ShiroConfig { ...@@ -191,9 +212,10 @@ public class ShiroConfig {
* *
* @return * @return
*/ */
private Map<String, Filter> getFilterMap(ShiroLoginService shiroLoginService) { private Map<String, Filter> getFilterMap(ShiroLoginService shiroLoginService, ApplicationService applicationService) {
Map<String, Filter> filterMap = new LinkedHashMap<>(); Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put(JWT_FILTER_NAME, new JwtFilter(shiroLoginService)); filterMap.put(JWT_FILTER_NAME, new JwtFilter(shiroLoginService));
filterMap.put("signatureAuthFilter", new SignatureAuthFilter(applicationService));
return filterMap; return filterMap;
} }
...@@ -256,6 +278,7 @@ public class ShiroConfig { ...@@ -256,6 +278,7 @@ public class ShiroConfig {
// 如果启用shiro,则设置最后一个设置为JWTFilter,否则全部路径放行 // 如果启用shiro,则设置最后一个设置为JWTFilter,否则全部路径放行
if (shiroProperties.isEnable()) { if (shiroProperties.isEnable()) {
filterChainDefinitionMap.put("/imClient/registerClient", "signatureAuthFilter");
filterChainDefinitionMap.put("/**", JWT_FILTER_NAME); filterChainDefinitionMap.put("/**", JWT_FILTER_NAME);
} else { } else {
filterChainDefinitionMap.put("/**", ANON); filterChainDefinitionMap.put("/**", ANON);
......
...@@ -16,18 +16,20 @@ ...@@ -16,18 +16,20 @@
package io.geekidea.springbootplus.config; package io.geekidea.springbootplus.config;
import com.alibaba.fastjson.JSON;
import com.wecloud.im.interceptor.DownloadInterceptor;
import com.wecloud.im.interceptor.ResourceInterceptor;
import com.wecloud.im.interceptor.UploadInterceptor;
import io.geekidea.springbootplus.config.properties.SpringBootPlusFilterProperties; import io.geekidea.springbootplus.config.properties.SpringBootPlusFilterProperties;
import io.geekidea.springbootplus.config.properties.SpringBootPlusInterceptorProperties; import io.geekidea.springbootplus.config.properties.SpringBootPlusInterceptorProperties;
import io.geekidea.springbootplus.config.properties.SpringBootPlusProperties; import io.geekidea.springbootplus.config.properties.SpringBootPlusProperties;
import io.geekidea.springbootplus.framework.core.filter.ChannelFilter;
import io.geekidea.springbootplus.framework.core.filter.RequestDetailFilter; import io.geekidea.springbootplus.framework.core.filter.RequestDetailFilter;
import io.geekidea.springbootplus.framework.core.interceptor.PermissionInterceptor; import io.geekidea.springbootplus.framework.core.interceptor.PermissionInterceptor;
import io.geekidea.springbootplus.framework.core.xss.XssFilter; import io.geekidea.springbootplus.framework.core.xss.XssFilter;
import io.geekidea.springbootplus.framework.util.IniUtil; import io.geekidea.springbootplus.framework.util.IniUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
...@@ -37,8 +39,10 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; ...@@ -37,8 +39,10 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.PostConstruct; import com.alibaba.fastjson.JSON;
import java.util.Map; import com.wecloud.im.interceptor.DownloadInterceptor;
import com.wecloud.im.interceptor.ResourceInterceptor;
import com.wecloud.im.interceptor.UploadInterceptor;
/** /**
* WebMvc配置 * WebMvc配置
...@@ -100,6 +104,16 @@ public class SpringBootPlusWebMvcConfig implements WebMvcConfigurer { ...@@ -100,6 +104,16 @@ public class SpringBootPlusWebMvcConfig implements WebMvcConfigurer {
return filterRegistrationBean; return filterRegistrationBean;
} }
@Bean
public FilterRegistrationBean repeatedlyReadFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
ChannelFilter repeatedlyReadFilter = new ChannelFilter();
registration.setFilter(repeatedlyReadFilter);
registration.setOrder(3);
registration.addUrlPatterns("/*");
return registration;
}
/** /**
* 自定义权限拦截器 * 自定义权限拦截器
......
package com.wecloud.im.entity; package com.wecloud.im.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity; import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.geekidea.springbootplus.framework.shiro.signature.Application;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.util.Date; import java.util.Date;
import javax.validation.constraints.NotNull;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
/** /**
* 第三方应用表 * 第三方应用表
* *
...@@ -22,7 +25,7 @@ import java.util.Date; ...@@ -22,7 +25,7 @@ import java.util.Date;
@Accessors(chain = true) @Accessors(chain = true)
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImApplication对象") @ApiModel(value = "ImApplication对象")
public class ImApplication extends BaseEntity { public class ImApplication extends BaseEntity implements Application {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@NotNull(message = "应用appid不能为空") @NotNull(message = "应用appid不能为空")
...@@ -65,4 +68,9 @@ public class ImApplication extends BaseEntity { ...@@ -65,4 +68,9 @@ public class ImApplication extends BaseEntity {
@ApiModelProperty("创建会话时对比扩展字段 0不 1是") @ApiModelProperty("创建会话时对比扩展字段 0不 1是")
private Integer contrastExtendedFieldStatus; private Integer contrastExtendedFieldStatus;
@Override
public Boolean isActive() {
return true;
}
} }
...@@ -15,13 +15,6 @@ import javax.validation.constraints.NotNull; ...@@ -15,13 +15,6 @@ import javax.validation.constraints.NotNull;
public class RegisterClientParam { public class RegisterClientParam {
/** /**
* appKey
*/
@NotNull(message = "appKey 不能为空")
@ApiModelProperty("appKey")
private String appKey;
/**
* app 用户id * app 用户id
*/ */
@NotNull(message = "用户id 不能为空") @NotNull(message = "用户id 不能为空")
......
package com.wecloud.im.service.impl; package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.mapper.ImApplicationMapper;
import com.wecloud.im.param.ImApplicationPageParam;
import com.wecloud.im.param.ImApplicationQueryVo;
import com.wecloud.im.service.ImApplicationService;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl; import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo; import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.signature.Application;
import io.geekidea.springbootplus.framework.shiro.signature.ApplicationService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
...@@ -20,6 +14,16 @@ import org.springframework.cache.annotation.Cacheable; ...@@ -20,6 +14,16 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.mapper.ImApplicationMapper;
import com.wecloud.im.param.ImApplicationPageParam;
import com.wecloud.im.param.ImApplicationQueryVo;
import com.wecloud.im.service.ImApplicationService;
/** /**
* 第三方应用表 服务实现类 * 第三方应用表 服务实现类
* *
...@@ -29,7 +33,7 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -29,7 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
@Slf4j @Slf4j
@Service @Service
@CacheConfig(cacheNames = "appl") @CacheConfig(cacheNames = "appl")
public class ImApplicationServiceImpl extends BaseServiceImpl<ImApplicationMapper, ImApplication> implements ImApplicationService { public class ImApplicationServiceImpl extends BaseServiceImpl<ImApplicationMapper, ImApplication> implements ImApplicationService, ApplicationService {
@Autowired @Autowired
private ImApplicationMapper imApplicationMapper; private ImApplicationMapper imApplicationMapper;
...@@ -90,4 +94,8 @@ public class ImApplicationServiceImpl extends BaseServiceImpl<ImApplicationMappe ...@@ -90,4 +94,8 @@ public class ImApplicationServiceImpl extends BaseServiceImpl<ImApplicationMappe
return new Paging<ImApplicationQueryVo>(iPage); return new Paging<ImApplicationQueryVo>(iPage);
} }
@Override
public Application getApplication(String appKey) {
return getCacheAppByAppKey(appKey);
}
} }
...@@ -6,6 +6,7 @@ import io.geekidea.springbootplus.framework.core.pagination.PageInfo; ...@@ -6,6 +6,7 @@ import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken; import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.geekidea.springbootplus.framework.shiro.util.SecurityUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Date; import java.util.Date;
...@@ -326,16 +327,16 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien ...@@ -326,16 +327,16 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien
@Override @Override
public Long registerClient(RegisterClientParam param) { public Long registerClient(RegisterClientParam param) {
ImApplication imApplication = imApplicationService.getCacheAppByAppKey(param.getAppKey()); Long appId = SecurityUtils.getCurrentAppId();
// 判断client是否存在 // 判断client是否存在
ImClient imClient = getOne(new QueryWrapper<ImClient>().lambda() ImClient imClient = getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId()) .eq(ImClient::getFkAppid, appId)
.eq(ImClient::getClientId, param.getUserId())); .eq(ImClient::getClientId, param.getUserId()));
if (imClient == null) { if (imClient == null) {
imClient = new ImClient(); imClient = new ImClient();
imClient.setId(SnowflakeUtil.getId()); imClient.setId(SnowflakeUtil.getId());
imClient.setFkAppid(imApplication.getId()); imClient.setFkAppid(appId);
imClient.setClientId(param.getUserId().toString()); imClient.setClientId(param.getUserId().toString());
imClient.setHeadPortrait(param.getHeadPortrait()); imClient.setHeadPortrait(param.getHeadPortrait());
imClient.setNickname(param.getNickname()); imClient.setNickname(param.getNickname());
...@@ -343,7 +344,7 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien ...@@ -343,7 +344,7 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien
ImClientDevice imClientDevice = new ImClientDevice(); ImClientDevice imClientDevice = new ImClientDevice();
imClientDevice.setId(SnowflakeUtil.getId()); imClientDevice.setId(SnowflakeUtil.getId());
imClientDevice.setFkAppid(imApplication.getId()); imClientDevice.setFkAppid(appId);
imClientDevice.setFkClientId(imClient.getId()); imClientDevice.setFkClientId(imClient.getId());
imClientDevice.setValid(1); imClientDevice.setValid(1);
imClientDevice.setDeviceType(param.getDeviceType()); imClientDevice.setDeviceType(param.getDeviceType());
......
package io.geekidea.springbootplus.framework.core.filter;
import io.geekidea.springbootplus.framework.shiro.signature.RequestWrapper;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
/**
*
* @Author luozh
* @Date 2022年04月15日 10:12
* @Version 1.0
*/
@WebFilter(urlPatterns = "/*", filterName = "channelFilter")
public class ChannelFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (servletRequest instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
}
if (requestWrapper == null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
}
}
package io.geekidea.springbootplus.framework.shiro.signature;
/**
*
* @Author luozh
* @Date 2022年04月15日 19:21
* @Version 1.0
*/
public interface Application {
/**
* 获取id
* @return
*/
Long getId();
/**
* 获取appKey
* @return
*/
String getAppKey();
/**
* 获取AppSecret
* @return
*/
String getAppSecret();
/**
* 客户端是否有效
* @return
*/
Boolean isActive();
}
package io.geekidea.springbootplus.framework.shiro.signature;
/**
*
* @Author luozh
* @Date 2022年04月15日 11:02
* @Version 1.0
*/
public interface ApplicationService {
/**
* 根据appKey获取对应的AppSecret
* @Author luozh
* @Date 2022年04月15日 11:02:53
* @param appKey
* @Return
*/
Application getApplication(String appKey);
}
package io.geekidea.springbootplus.framework.shiro.signature;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Base64;
public class BinaryUtil {
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F'};
public static String toBase64String(byte[] binaryData) {
return new String(Base64.encodeBase64(binaryData));
}
public static byte[] fromBase64String(String base64String) {
return Base64.decodeBase64(base64String);
}
public static byte[] calculateMd5(byte[] binaryData) {
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 algorithm not found.");
}
messageDigest.update(binaryData);
return messageDigest.digest();
}
public static String encodeMD5(byte[] binaryData) {
byte[] md5Bytes = calculateMd5(binaryData);
int len = md5Bytes.length;
char buf[] = new char[len * 2];
for (int i = 0; i < len; i++) {
buf[i * 2] = HEX_DIGITS[(md5Bytes[i] >>> 4) & 0x0f];
buf[i * 2 + 1] = HEX_DIGITS[md5Bytes[i] & 0x0f];
}
return new String(buf);
}
}
package io.geekidea.springbootplus.framework.shiro.signature;
/**
*
* @Author luozh
* @Date 2022年04月14日 14:55
* @Version 1.0
*/
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* Used for computing Hmac-SHA256 signature.
*/
public class HmacSHA256Signature {
/* The default encoding. */
private static final String DEFAULT_ENCODING = "UTF-8";
/* Signature method. */
private static final String ALGORITHM = "HmacSHA256";
/* Signature version. */
private static final String VERSION = "1";
private static final Object LOCK = new Object();
/* Prototype of the Mac instance. */
private static Mac macInstance;
public String getAlgorithm() {
return ALGORITHM;
}
public String getVersion() {
return VERSION;
}
public String computeSignature(String key, String data) {
try {
byte[] signData = sign(key.getBytes(DEFAULT_ENCODING), data.getBytes(DEFAULT_ENCODING), macInstance,
LOCK, ALGORITHM);
return BinaryUtil.toBase64String(signData);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("Unsupported algorithm: " + DEFAULT_ENCODING, ex);
}
}
protected byte[] sign(byte[] key, byte[] data, Mac macInstance, Object lock, String algorithm) {
try {
// Because Mac.getInstance(String) calls a synchronized method, it
// could block on
// invoked concurrently, so use prototype pattern to improve perf.
if (macInstance == null) {
synchronized (lock) {
if (macInstance == null) {
macInstance = Mac.getInstance(algorithm);
}
}
}
Mac mac;
try {
mac = (Mac) macInstance.clone();
} catch (CloneNotSupportedException e) {
// If it is not clonable, create a new one.
mac = Mac.getInstance(algorithm);
}
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException("Unsupported algorithm: " + algorithm, ex);
} catch (InvalidKeyException ex) {
throw new RuntimeException("Invalid key: " + key, ex);
}
}
}
...@@ -2,8 +2,8 @@ package io.geekidea.springbootplus.framework.shiro.signature; ...@@ -2,8 +2,8 @@ package io.geekidea.springbootplus.framework.shiro.signature;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import javax.servlet.ReadListener; import javax.servlet.ReadListener;
...@@ -11,8 +11,6 @@ import javax.servlet.ServletInputStream; ...@@ -11,8 +11,6 @@ import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.io.IOUtils;
/** /**
* 对HttpServletRequest进行重写, * 对HttpServletRequest进行重写,
* 1、用来接收application/json参数数据类型,即@RequestBody注解标注的参数,解决多次读取问题 * 1、用来接收application/json参数数据类型,即@RequestBody注解标注的参数,解决多次读取问题
...@@ -26,37 +24,51 @@ import org.apache.commons.io.IOUtils; ...@@ -26,37 +24,51 @@ import org.apache.commons.io.IOUtils;
* @Version 1.0 * @Version 1.0
*/ */
public class RequestWrapper extends HttpServletRequestWrapper { public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
//参数字节数组 public RequestWrapper(HttpServletRequest request) {
private byte[] requestBody;
//Http请求对象
private HttpServletRequest request;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request); super(request);
this.request = request; StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
} }
} else {
/** stringBuilder.append("");
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
/**
* 每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中
* 解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题
*/
if (null == this.requestBody) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(request.getInputStream(), baos);
this.requestBody = baos.toByteArray();
} }
} catch (IOException ex) {
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody); } finally {
return new ServletInputStream() { if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override @Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() { public boolean isFinished() {
return false; return false;
} }
...@@ -67,23 +79,25 @@ public class RequestWrapper extends HttpServletRequestWrapper { ...@@ -67,23 +79,25 @@ public class RequestWrapper extends HttpServletRequestWrapper {
} }
@Override @Override
public void setReadListener(ReadListener listener) { public void setReadListener(ReadListener readListener) {
} }
@Override @Override
public int read() { public int read() throws IOException {
return bais.read(); return byteArrayInputStream.read();
} }
}; };
} return servletInputStream;
public byte[] getRequestBody() {
return requestBody;
} }
@Override @Override
public BufferedReader getReader() throws IOException { public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream())); return new BufferedReader(new InputStreamReader(this.getInputStream()));
} }
public String getBody() {
return this.body;
}
} }
package io.geekidea.springbootplus.framework.shiro.signature;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.TreeMap;
import cn.hutool.core.lang.Assert;
/**
* 签名工具类
* @Author luozh
* @Date 2022年04月14日 11:32o
* @Version 1.0
*/
public class SignUtils {
public static final String IM_PREFIX = "x-im-";
public static final String CONTENT_TYPE = "Content-Type";
public static final String DATE = "Date";
public static final String NEW_LINE = "\n";
public static String buildCanonicalString(String method, String resourcePath, Map<String, String> headers, Map<String, String> parameters) {
StringBuilder canonicalString = new StringBuilder();
canonicalString.append(method).append(NEW_LINE);
TreeMap<String, String> fixedHeadersToSign = new TreeMap<>();
TreeMap<String, String> canonicalizedImHeadersToSign = new TreeMap<>();
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
if (header.getKey() != null) {
String lowerKey = header.getKey().toLowerCase();
if (lowerKey.equals(CONTENT_TYPE.toLowerCase())
|| lowerKey.equals(DATE.toLowerCase())) {
fixedHeadersToSign.put(lowerKey, header.getValue().trim());
} else if (lowerKey.startsWith(IM_PREFIX)) {
canonicalizedImHeadersToSign.put(lowerKey, header.getValue().trim());
}
}
}
}
if (!fixedHeadersToSign.containsKey(CONTENT_TYPE.toLowerCase())) {
fixedHeadersToSign.put(CONTENT_TYPE.toLowerCase(), "");
}
// Append fixed headers to sign to canonical string
for (Map.Entry<String, String> entry : fixedHeadersToSign.entrySet()) {
Object value = entry.getValue();
canonicalString.append(value);
canonicalString.append(NEW_LINE);
}
// Append canonicalized im headers to sign to canonical string
for (Map.Entry<String, String> entry : canonicalizedImHeadersToSign.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
canonicalString.append(key).append(':').append(value).append(NEW_LINE);
}
// Append canonical resource to canonical string
canonicalString.append(buildCanonicalizedResource(resourcePath, parameters));
return canonicalString.toString();
}
private static String buildCanonicalizedResource(String resourcePath, Map<String, String> parameters) {
Assert.isTrue(resourcePath.startsWith("/"), "Resource path should start with slash character");
StringBuilder builder = new StringBuilder();
builder.append(uriEncoding(resourcePath));
if (parameters != null) {
TreeMap<String, String> canonicalizedParams = new TreeMap<String, String>();
for (Map.Entry<String, String> param : parameters.entrySet()) {
if (param.getValue() != null) {
canonicalizedParams.put(uriEncoding(param.getKey()), uriEncoding(param.getValue()));
} else {
canonicalizedParams.put(uriEncoding(param.getKey()), null);
}
}
char separator = '?';
for (Map.Entry<String, String> entry : canonicalizedParams.entrySet()) {
builder.append(separator);
builder.append(entry.getKey());
if (entry.getValue() != null && !entry.getValue().isEmpty()) {
builder.append("=").append(entry.getValue());
}
separator = '&';
}
}
return builder.toString();
}
public static String uriEncoding(String uri) {
String result = "";
try {
for (char c : uri.toCharArray()) {
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9') || c == '_' || c == '-'
|| c == '~' || c == '.') {
result += c;
} else if (c == '/') {
result += "%2F";
} else {
byte[] b;
b = Character.toString(c).getBytes("utf-8");
for (int i = 0; i < b.length; i++) {
int k = b[i];
if (k < 0) {
k += 256;
}
result += "%" + Integer.toHexString(k).toUpperCase();
}
}
}
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
return result;
}
public static String buildSignature(String secretAccessKey, String httpMethod, String resourcePath, Map<String, String> headers, Map<String, String> parameters) {
String canonicalString = buildCanonicalString(httpMethod, resourcePath, headers, parameters);
return new HmacSHA256Signature().computeSignature(secretAccessKey, canonicalString);
}
}
package io.geekidea.springbootplus.framework.shiro.signature; package io.geekidea.springbootplus.framework.shiro.signature;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter; import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.web.context.request.RequestContextHolder; import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.springframework.web.context.request.ServletRequestAttributes; import org.apache.shiro.web.util.WebUtils;
/** /**
* shiro 用户签名认证 * shiro 用户签名认证
...@@ -17,27 +20,96 @@ import org.springframework.web.context.request.ServletRequestAttributes; ...@@ -17,27 +20,96 @@ import org.springframework.web.context.request.ServletRequestAttributes;
* @Date 2022年04月14日 16:43 * @Date 2022年04月14日 16:43
* @Version 1.0 * @Version 1.0
*/ */
@Slf4j
public class SignatureAuthFilter extends AuthenticatingFilter { public class SignatureAuthFilter extends AuthenticatingFilter {
private static final String AUTHORIZATION = "Authorization"; private static final String AUTHORIZATION = "Authorization";
private ApplicationService applicationService;
public SignatureAuthFilter(@NotNull ApplicationService applicationService) {
if (applicationService == null) {
throw new IllegalArgumentException("application service must not be null");
}
this.applicationService = applicationService;
}
@Override @Override
protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
ShiroHttpServletRequest ShiroHttpServletRequest = (ShiroHttpServletRequest) servletRequest;
HttpServletRequest request = HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); (HttpServletRequest) ShiroHttpServletRequest.getRequest();
String token = request.getHeader(AUTHORIZATION); String authorization = request.getHeader(AUTHORIZATION);
if (StringUtils.isBlank(token)) { if (StringUtils.isBlank(authorization)) {
throw new AuthenticationException("token不能为空"); throw new AuthenticationException("token不能为空");
} }
// 校验Signature是否完整 合规
if (!authorization.startsWith("WECLOUD-IM AppKey")) {
throw new AuthenticationException("token错误");
}
if (!authorization.contains(", Signature:")) {
throw new AuthenticationException("token 未包含签名信息");
}
String appKey = getAppKeyFromAuthorization(authorization);
String clientSignature = getSignatureFromAuthorization(authorization);
return null; // 校验通过 获取并校验Application信息
Application application = applicationService.getApplication(appKey);
if (application == null) {
throw new AuthenticationException("application does not exist");
}
if (!application.isActive()) {
throw new AuthenticationException("application is unavailable");
}
Long appId = application.getId();
String appSecret = application.getAppSecret();
SignatureChecker.check(request, clientSignature, appSecret);
// 构建SignatureAuthToken
return new SignatureAuthToken(appKey, appId);
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
String url = WebUtils.toHttp(request).getRequestURI();
log.info("isAccessAllowed url:{}", url);
if (this.isLoginRequest(request, response)) {
return true;
}
boolean allowed = false;
try {
allowed = executeLogin(request, response);
} catch (IllegalStateException e) { //not found any token
log.error("Token不能为空", e);
} catch (Exception e) {
log.error("访问错误", e);
}
return true;
} }
@Override @Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
return false; return false;
} }
private String getAppKeyFromAuthorization(String authorization) {
// 处理token
String[] tokenInfo = authorization.split(",");
// appkey 格式是固定的,直接替换
return tokenInfo[0].replace("WECLOUD-IM AppKey:", "").trim();
}
private String getSignatureFromAuthorization(String authorization) {
// 处理token
String[] tokenInfo = authorization.split(",");
// 客户端传入的签名信息
return tokenInfo[1].replace("Signature:", "").trim();
}
} }
package io.geekidea.springbootplus.framework.shiro.signature;
import org.apache.commons.collections4.SetUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
*
* @Author luozh
* @Date 2022年04月15日 17:21
* @Version 1.0
*/
public class SignatureAuthRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 设置角色
authorizationInfo.setRoles(SetUtils.hashSet("client:all"));
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 校验token
SignatureAuthToken token = (SignatureAuthToken) authenticationToken;
if (token == null) {
throw new AuthenticationException("token不能为空");
}
return new SimpleAuthenticationInfo(
token,
token.getCredentials(),
getName()
);
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof SignatureAuthToken;
}
}
package io.geekidea.springbootplus.framework.shiro.signature;
import io.geekidea.springbootplus.framework.util.IpUtil;
import lombok.Data;
import org.apache.shiro.authc.HostAuthenticationToken;
/**
*
* @Author luozh
* @Date 2022年04月15日 15:19
* @Version 1.0
*/
@Data
public class SignatureAuthToken implements HostAuthenticationToken {
/**
* 登录ip
*/
private String host;
/**
* appKey
*/
private String appKey;
/**
* appId
*/
private Long appId;
public SignatureAuthToken(String appKey, Long appId) {
this.appKey = appKey;
this.appId = appId;
setHost(IpUtil.getRequestIp());
}
@Override
public Object getPrincipal() {
return appKey;
}
@Override
public Object getCredentials() {
return appKey;
}
}
package io.geekidea.springbootplus.framework.shiro.signature; package io.geekidea.springbootplus.framework.shiro.signature;
import java.nio.charset.StandardCharsets;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
...@@ -9,6 +8,7 @@ import java.util.Map; ...@@ -9,6 +8,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
...@@ -33,34 +33,57 @@ public class SignatureChecker { ...@@ -33,34 +33,57 @@ public class SignatureChecker {
* @Author luozh * @Author luozh
* @Date 2022年04月14日 05:32:32 * @Date 2022年04月14日 05:32:32
* @param request 请求信息 * @param request 请求信息
* @param signature 签名 * @param clientSignature 签名
* @param appSecret app秘钥
* @Return appKey * @Return appKey
*/ */
public static String check(HttpServletRequest request, String signature) { public static void check(HttpServletRequest request, String clientSignature, String appSecret) {
// 获取到入参
Map<String, String> params = getParameterMap(request);
// 获取请求头
Map<String, String> headers = getHeaderMap(request);
// resourcePath
String resourcePath = request.getRequestURI();
// request methos
String requestMethod = request.getMethod();
String serverSignature = SignUtils.buildSignature(appSecret, requestMethod, resourcePath, headers, params);
if (!serverSignature.equals(clientSignature)) {
// 返回给用户的response中告诉用户正确的用于验证加密的签名字符串
throw new AuthenticationException("token 错误");
}
}
public static Map<String, String> getHeaderMap(HttpServletRequest servletRequest) {
Map<String, String> headerMap = new LinkedHashMap<>();
Enumeration<String> names = servletRequest.getHeaderNames();
while (names.hasMoreElements()) {
String key = names.nextElement();
headerMap.put(key, servletRequest.getHeader(key));
}
return ""; return headerMap;
} }
/** /**
* 获取请求入参 * 获取请求入参
* *
* @param request * @param servletRequest
* @return * @return
*/ */
public static Map<String, Object> getParameterMap(HttpServletRequest request) { public static Map<String, String> getParameterMap(HttpServletRequest servletRequest) {
Map<String, Object> paramMap = new LinkedHashMap<>(); Map<String, String> paramMap = new LinkedHashMap<>();
if (request instanceof RequestWrapper) {
RequestWrapper requestWrapper = (RequestWrapper) request; if (servletRequest instanceof RequestWrapper) {
Map<String, Object> body = getParameterMap(requestWrapper.getRequestBody()); RequestWrapper requestWrapper = (RequestWrapper) servletRequest;
Map<String, String> body = getParameterMap(requestWrapper.getBody());
if (!CollectionUtils.isEmpty(body)) { if (!CollectionUtils.isEmpty(body)) {
paramMap.putAll(body); paramMap.putAll(body);
} }
} }
Enumeration<String> names = request.getParameterNames(); Enumeration<String> names = servletRequest.getParameterNames();
while (names.hasMoreElements()) { while (names.hasMoreElements()) {
String key = names.nextElement(); String key = names.nextElement();
paramMap.put(key, request.getParameter(key)); paramMap.put(key, servletRequest.getParameter(key));
} }
return paramMap; return paramMap;
...@@ -72,11 +95,11 @@ public class SignatureChecker { ...@@ -72,11 +95,11 @@ public class SignatureChecker {
* @param params * @param params
* @return * @return
*/ */
public static Map<String, Object> getParameterMap(byte[] params) { public static Map<String, String> getParameterMap(String params) {
try { try {
return JSON.parseObject(new String(params), Map.class); return (Map<String, String>) JSON.parseObject(params, Map.class);
} catch (Exception e) { } catch (Exception e) {
return convertParameterToMap(new String(params, StandardCharsets.UTF_8)); return convertParameterToMap(params);
} }
} }
...@@ -87,11 +110,11 @@ public class SignatureChecker { ...@@ -87,11 +110,11 @@ public class SignatureChecker {
* @param param * @param param
* @return * @return
*/ */
public static Map<String, Object> convertParameterToMap(String param) { public static Map<String, String> convertParameterToMap(String param) {
if (StringUtils.isEmpty(param)) { if (StringUtils.isEmpty(param)) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
Map<String, Object> pMap = Maps.newLinkedHashMap(); Map<String, String> pMap = Maps.newLinkedHashMap();
String[] pArray = StringUtils.split(param, "&"); String[] pArray = StringUtils.split(param, "&");
for (int i = 0; i < pArray.length; i++) { for (int i = 0; i < pArray.length; i++) {
String[] array = StringUtils.split(pArray[i], "="); String[] array = StringUtils.split(pArray[i], "=");
......
...@@ -16,23 +16,25 @@ ...@@ -16,23 +16,25 @@
package io.geekidea.springbootplus.framework.shiro.util; package io.geekidea.springbootplus.framework.shiro.util;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.geekidea.springbootplus.config.constant.CommonConstant; import io.geekidea.springbootplus.config.constant.CommonConstant;
import io.geekidea.springbootplus.config.properties.JwtProperties; import io.geekidea.springbootplus.config.properties.JwtProperties;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken; import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.util.UUIDUtil; import io.geekidea.springbootplus.framework.util.UUIDUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.util.Date;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import com.alibaba.fastjson.JSON;
import java.util.Date; import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
/** /**
* JWT工具类 * JWT工具类
......
package io.geekidea.springbootplus.framework.shiro.util;
import io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthToken;
/**
*
* @Author luozh
* @Date 2022年04月15日 19:57
* @Version 1.0
*/
public class SecurityUtils {
/**
* 获取当前签名token
* @Author luozh
* @Date 2022年04月15日 07:53:54
* @param
* @Return 签名token
*/
public static SignatureAuthToken getCurrentSignatureAuthToken() {
return (SignatureAuthToken) org.apache.shiro.SecurityUtils.getSubject().getPrincipal();
}
/**
* 获取当前请求appId
* @Author luozh
* @Date 2022年04月15日 07:58:36
* @param
* @Return
*/
public static Long getCurrentAppId() {
return getCurrentSignatureAuthToken().getAppId();
}
/**
* 获取当前请求appKey
* @Author luozh
* @Date 2022年04月15日 07:58:56
* @param
* @Return
*/
public static String getCurrentAppKey() {
return getCurrentSignatureAuthToken().getAppKey();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment