Commit f03bdf7b authored by xfxmcy's avatar xfxmcy

education spcl 集成

parent 57c2bc6c
package org.rcisoft.config;
import feign.Feign;
import okhttp3.ConnectionPool;
import org.rcisoft.core.auth.config.CyOkHttpTokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
/**
* Created by lcy on 18/4/9.
*
* feign config
*/
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Configuration
@ConditionalOnClass(Feign.class)
public class CyFeignOkHttpConfig {
@Autowired
CyOkHttpTokenInterceptor rcOkHttpTokenInterceptor;
private int feignOkHttpReadTimeout = 60;
private int feignConnectTimeout = 60;
private int feignWriteTimeout = 120;
@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder().readTimeout(feignOkHttpReadTimeout, TimeUnit.SECONDS).connectTimeout(feignConnectTimeout, TimeUnit.SECONDS)
.writeTimeout(feignWriteTimeout, TimeUnit.SECONDS).connectionPool(new ConnectionPool())
.addInterceptor(rcOkHttpTokenInterceptor)
.build();
}
}
package org.rcisoft.core.auth.config;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.rcisoft.core.auth.constant.CyAuthConstants;
import org.rcisoft.core.util.CyServiceAuthUtil;
import org.rcisoft.core.util.CyStrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* Created by lcy on 18/4/9.
*/
@Component
@Slf4j
public class CyOkHttpTokenInterceptor implements Interceptor {
@Autowired
@Lazy
public CyServiceAuthUtil rcServiceAuthUtil;
@Autowired
@Lazy
private CyServiceAuthConfig rcServiceAuthConfig;
/**
* 追加token
* @param chain
* @return
* @throws IOException
*/
@Override
public Response intercept(Chain chain) throws IOException {
log.info("url: " + chain.request().url().toString());
Request newRequest = null;
/** 访问 服务 token **/
if (chain.request().url().toString().contains("/client/token")) {
newRequest = chain.request()
.newBuilder()
.build();
} else {
newRequest = chain.request()
.newBuilder()
.header(rcServiceAuthConfig.getTokenHeader(),
CyStrUtil.getObjectValue(rcServiceAuthUtil.getClientToken()))
.build();
}
Response response = chain.proceed(newRequest);
if (HttpStatus.FORBIDDEN.value() == response.code()) {
/*客户端token异常*/
if (response.body().string().contains(String.valueOf(CyAuthConstants.EX_CLIENT_INVALID_CODE))) {
log.info("Client Token Expire,Retry to request...");
rcServiceAuthUtil.refreshClientToken();
newRequest = chain.request()
.newBuilder()
.header(rcServiceAuthConfig.getTokenHeader(), rcServiceAuthUtil.getClientToken())
.build();
response = chain.proceed(newRequest);
}
}
/*else {
String json = null;
ResponseBody responseBody = response.body();
if (null != responseBody)
json = responseBody.string();
CyScResult result = null;
try {
result = JSONObject.parseObject(json, CyScResult.class);
log.info("---" + result);
if(null != result && CyScResultCode.SUCCESS.code != result.getCode())
throw new ServiceException(ResultServiceEnums.FAIL);
}catch (Exception e){
log.error(e.getMessage());
}
}*/
return response;
}
}
package org.rcisoft.core.auth.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
/**
* Created with family.
* author: cy
* Date: 2019/11/28
* Time: 10:55 AM
* description:
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CyServiceAuthConfig {
private byte[] pubKeyByte;
@Value("${auth.client.id:null}")
private String clientId;
@Value("${auth.client.secret}")
private String clientSecret;
@Value("${auth.client.token-header}")
private String tokenHeader;
@Value("${spring.application.name}")
private String applicationName;
public String getClientId() {
return "null".equals(clientId) ? applicationName : clientId;
}
}
package org.rcisoft.core.auth.constant;
/**
* Created by ace on 2017/8/29.
*/
public class CyAuthConstants {
public final static String RESOURCE_TYPE_MENU = "menu";
public final static String RESOURCE_TYPE_BTN = "button";
public static final Integer EX_TOKEN_ERROR_CODE = 40101;
// 用户token异常
public static final Integer EX_USER_INVALID_CODE = 40102;
// 客户端token异常
public static final Integer EX_CLIENT_INVALID_CODE = 40131;
public static final Integer EX_CLIENT_FORBIDDEN_CODE = 40331;
public static final Integer EX_OTHER_CODE = 500;
public static final String CONTEXT_KEY_USER_ID = "currentUserId";
public static final String CONTEXT_KEY_USERNAME = "currentUserName";
public static final String CONTEXT_KEY_USER_NAME = "currentUser";
public static final String CONTEXT_KEY_USER_TOKEN = "currentUserToken";
public static final String JWT_KEY_USER_ID = "userId";
public static final String JWT_KEY_NAME = "name";
}
package org.rcisoft.core.auth.feign;
import org.rcisoft.core.result.CyResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by lcy on 18/4/9.
*/
@FeignClient(value = "${auth.serviceId}",configuration = {} , fallback = CyAuthServerFeignFallBack.class)
public interface CyAuthServerFeign {
@RequestMapping(value = "/client/myClient")
public CyResult getAllowedClient(@RequestParam("serviceId") String serviceId, @RequestParam("secret") String secret);
@RequestMapping(value = "/client/token",method = RequestMethod.POST)
public CyResult getAccessToken(@RequestParam("clientId") String clientId, @RequestParam("secret") String secret);
@RequestMapping(value = "/client/servicePubKey",method = RequestMethod.POST)
public CyResult getServicePublicKey(@RequestParam("clientId") String clientId, @RequestParam("secret") String secret);
}
package org.rcisoft.core.auth.feign;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.core.enums.CyResultCode;
import org.rcisoft.core.result.CyMessCons;
import org.rcisoft.core.result.CyResult;
import org.rcisoft.core.result.CyResultGenUtil;
/**
* Created with family.
* author: cy
* Date: 2019/12/4
* Time: 2:20 PM
* description:
*/
@Slf4j
public class CyAuthServerFeignFallBack implements CyAuthServerFeign {
@Override
public CyResult getAllowedClient(String serviceId, String secret) {
log.error("spcl-auth cyAuthServerFeign getAllowedClient fall...");
return CyResultGenUtil.builderOriginResult(
CyResultCode.SERVER_TIMEOUT.getCode(),
CyMessCons.MESSAGE_ALERT_OVERTIME,
null);
}
@Override
public CyResult getAccessToken(String clientId, String secret) {
log.error("spcl-auth cyAuthServerFeign getAccessToken fall...");
return CyResultGenUtil.builderOriginResult(
CyResultCode.SERVER_TIMEOUT.getCode(),
CyMessCons.MESSAGE_ALERT_OVERTIME,
null);
}
@Override
public CyResult getServicePublicKey(String clientId, String secret) {
log.error("spcl-auth cyAuthServerFeign getServicePublicKey fall...");
return CyResultGenUtil.builderOriginResult(
CyResultCode.SERVER_TIMEOUT.getCode(),
CyMessCons.MESSAGE_ALERT_OVERTIME,
null);
}
}
package org.rcisoft.core.enums;
/**
* Created with family.
* author: cy
* Date: 2020/3/16
* Time: 2:42 PM
* description:
*/
import lombok.Getter;
@Getter
public enum CyResultCode {
SUCCESS(200),//成功
FAIL(400),//失败
UNAUTHORIZED(401),//未认证(签名错误)
UNAUTHENTICATED(402),//未授权(权限不够)
SERVER_TIMEOUT(403),//服务延时 hystrix
NOT_FOUND(404),//接口不存在
INTERNAL_SERVER_ERROR(500),//服务器内部错误
PARAMETER_ERROR(601),//参数错误
PARAMETER_DECRYPT_ERROR(603),//参数解密错误
REDIS_OPERATE_ERROR(700),//redis 操作失败
DATA_EXISTS(602);//数据已存在
private int code;
CyResultCode(int code) {
this.code = code;
}
}
package org.rcisoft.core.result;
/**
* Created with family.
* author: cy
* Date: 2020/3/16
* Time: 2:52 PM
* description:
*/
public class CyMessCons {
//操作成功
public static final String MESSAGE_ALERT_SUCCESS = "操作成功";
//操作失败
public static final String MESSAGE_ALERT_ERROR = "操作失败";
//操作超时
public static final String MESSAGE_ALERT_OVERTIME = "操作超时";
//信息非法
public static final String MESSAGE_ALERT_INFO_INVALID = "信息不合法";
}
package org.rcisoft.core.result;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonView;
import org.rcisoft.core.enums.CyResultCode;
/**
* 统一API响应结果封装
*/
public class CyResult {
private Integer code;
private String message;
private Object data;
/**
*
* @param data
* @return
*/
public void setErrorMessage(String message, Object data) {
this.code = CyResultCode.FAIL.getCode();
this.message = message;
this.data = data;
}
public void setSucessMessage(String message, Object data) {
this.code = CyResultCode.SUCCESS.getCode();
this.message = message;
this.data = data;
}
public interface DefulatJsonView{}
/**
* desc Dec 20 解决 feign setter 重载方法 可能会冲突问题
* @param cyResultCode
* @return
*/
public CyResult setResultCode(CyResultCode cyResultCode) {
this.code = cyResultCode.getCode();
return this;
}
@JsonView(DefulatJsonView.class)
public Integer getCode() {
return code;
}
public CyResult setCode(Integer code) {
this.code = code;
return this;
}
@JsonView(DefulatJsonView.class)
public String getMessage() {
return message;
}
public CyResult setMessage(String message) {
this.message = message;
return this;
}
@JsonView(DefulatJsonView.class)
public Object getData() {
return data;
}
public CyResult setData(Object data) {
this.data = data;
return this;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
package org.rcisoft.core.result;
import org.rcisoft.core.enums.CyResultCode;
import org.rcisoft.core.exception.ServiceException;
import org.rcisoft.core.model.PersistModel;
/**
* Created with family.
* author: cy
* Date: 2020/3/16
* Time: 2:50 PM
* description:
*/
public class CyResultGenUtil {
private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";
public static CyResult builder(PersistModel dataModel, String sucMessage, String errMessage, Object data){
CyResult cyResult = new CyResult();
if(dataModel.isSuccessBySinglePersist())
cyResult.setSucessMessage(sucMessage,data);
else
cyResult.setErrorMessage(errMessage,data);
return cyResult;
}
public static CyResult genSuccessResult() {
return new CyResult()
.setResultCode(CyResultCode.SUCCESS)
.setMessage(DEFAULT_SUCCESS_MESSAGE);
}
public static CyResult genSuccessResult(Object data) {
return new CyResult()
.setResultCode(CyResultCode.SUCCESS)
.setMessage(DEFAULT_SUCCESS_MESSAGE)
.setData(data);
}
public static CyResult genFailResult(String message) {
return new CyResult()
.setResultCode(CyResultCode.FAIL)
.setMessage(message);
}
/**
* 构建原生 result
* @param code
* @param mess
* @param data
* @return
*/
public static CyResult builderOriginResult(Integer code,String mess,Object data){
return new CyResult()
.setCode(code)
.setMessage(mess)
.setData(data);
}
/**
* 验证 result
* @param result
* @return
*/
public static CyResult validateResult(CyResult result){
if(result.getCode() != CyResultCode.SUCCESS.getCode()){
throw new ServiceException(result.getCode(),result.getMessage());
}
return result;
}
}
package org.rcisoft.core.runner;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.core.auth.config.CyServiceAuthConfig;
import org.rcisoft.core.auth.feign.CyAuthServerFeign;
import org.rcisoft.core.result.CyResult;
import org.rcisoft.core.util.CyRsaKeyHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* Created by lcy on 18/4/9.
*
* 获取用户 client/user 公钥
*/
@Component
@Slf4j
public class CyAuthClientRunner implements CommandLineRunner {
@Autowired
private CyServiceAuthConfig rcServiceAuthConfig;
@Autowired
private CyAuthServerFeign rcAuthServerFeign;
@Override
public void run(String... args) throws Exception {
log.info("初始化加载服务端pubKey");
try {
refreshServicePubKey();
}catch(Exception e){
log.error("初始化加载服务端pubKey失败,1分钟后自动重试!",e);
}
}
/**
* 刷新service 公钥
*/
@Scheduled(cron = "0 0/10 * * * ?")
public void refreshServicePubKey() throws IOException{
CyResult resp = rcAuthServerFeign.getServicePublicKey(rcServiceAuthConfig.getClientId(), rcServiceAuthConfig.getClientSecret());
if (resp.getCode() == HttpStatus.OK.value()) {
Object data = resp.getData();
byte[] re = CyRsaKeyHelper.toBytes(data.toString());
this.rcServiceAuthConfig.setPubKeyByte(re);
}
}
}
package org.rcisoft.core.util;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* Created with family.
* author: cy
* Date: 2020/3/16
* Time: 3:02 PM
* description:
*/
public class CyRsaKeyHelper {
/**
* 获取公钥
*
* @param filename
* @return
* @throws Exception
*/
public PublicKey getPublicKey(String filename) throws Exception {
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(filename);
DataInputStream dis = new DataInputStream(resourceAsStream);
byte[] keyBytes = new byte[resourceAsStream.available()];
dis.readFully(keyBytes);
dis.close();
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
/**
* 获取密钥
*
* @param filename
* @return
* @throws Exception
*/
public PrivateKey getPrivateKey(String filename) throws Exception {
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(filename);
DataInputStream dis = new DataInputStream(resourceAsStream);
byte[] keyBytes = new byte[resourceAsStream.available()];
dis.readFully(keyBytes);
dis.close();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
/**
* 获取公钥
*
* @param publicKey
* @return
* @throws Exception
*/
public PublicKey getPublicKey(byte[] publicKey) throws Exception {
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
/**
* 获取密钥
*
* @param privateKey
* @return
* @throws Exception
*/
public PrivateKey getPrivateKey(byte[] privateKey) throws Exception {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
/**
* 生存rsa公钥和密钥
*
* @param publicKeyFilename
* @param privateKeyFilename
* @param password
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public void generateKey(String publicKeyFilename, String privateKeyFilename, String password) throws IOException, NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(password.getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
FileOutputStream fos = new FileOutputStream(publicKeyFilename);
fos.write(publicKeyBytes);
fos.close();
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
fos = new FileOutputStream(privateKeyFilename);
fos.write(privateKeyBytes);
fos.close();
}
/**
* 生存rsa公钥
*
* @param password
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public static byte[] generatePublicKey(String password) throws IOException, NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(password.getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
return keyPair.getPublic().getEncoded();
}
/**
* 生存rsa公钥
*
* @param password
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public static byte[] generatePrivateKey(String password) throws IOException, NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(password.getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
return keyPair.getPrivate().getEncoded();
}
public static Map<String, byte[]> generateKey(String password) throws IOException, NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(password.getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
Map<String, byte[]> map = new HashMap<String, byte[]>();
map.put("pub", publicKeyBytes);
map.put("pri", privateKeyBytes);
return map;
}
public static String toHexString(byte[] b) {
return (new BASE64Encoder()).encodeBuffer(b);
}
public static final byte[] toBytes(String s) throws IOException {
return (new BASE64Decoder()).decodeBuffer(s);
}
public static void main(String[] args) throws NoSuchAlgorithmException {
/*KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom("123".getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
System.out.println(keyPair.getPublic().getEncoded());*/
}
}
package org.rcisoft.core.util;
import lombok.extern.slf4j.Slf4j;
import org.rcisoft.core.auth.config.CyServiceAuthConfig;
import org.rcisoft.core.auth.feign.CyAuthServerFeign;
import org.rcisoft.core.result.CyResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by lcy on 18/4/9.
*/
@Component
@Slf4j
@EnableScheduling
public class CyServiceAuthUtil {
@Autowired
private CyServiceAuthConfig rcServiceAuthConfig;
@Autowired
private CyAuthServerFeign rcAuthServerFeign;
/**
* 允许调用的 client
*/
private List<String> allowedClient;
private String clientToken;
@Scheduled(cron = "0 0/10 * * * ?")
public void refreshClientToken() {
log.debug("refresh client token.....");
CyResult resp = rcAuthServerFeign.getAccessToken(rcServiceAuthConfig.getClientId(), rcServiceAuthConfig.getClientSecret());
if (resp.getCode() == 200)
this.clientToken = resp.getData().toString();
}
public String getClientToken() {
if (this.clientToken == null) {
this.refreshClientToken();
}
return clientToken;
}
}
package org.rcisoft.core.util;
import lombok.extern.slf4j.Slf4j;
/**
* Created with family.
* author: cy
* Date: 2020/3/16
* Time: 3:08 PM
* description:
*/
@Slf4j
public class CyStrUtil {
/**
* null ==> ""
* @param obj
* @return
*/
public static String getObjectValue(Object obj){
return obj == null ? "" : obj.toString();
}
/**
* null ==> null
* @param obj
* @return
*/
public static String getObjectValueOrNull(Object obj){
return obj == null ? null : obj.toString();
}
}
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