Browse Source

登录增加重定向功能

zhangqiankun 3 years ago
parent
commit
a2e5c6938e

+ 8 - 17
saas-account/src/main/java/com/persagy/account/controller/SaasAuthCenterController.java

@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import com.alibaba.fastjson.JSONObject;
 import com.persagy.account.config.ApplicationProperties;
+import com.persagy.account.manage.SaasAuthHandler;
 import com.persagy.account.pojo.vo.thirty.SaasCodeTokenVO;
 import com.persagy.account.pojo.vo.thirty.SaasCodeVO;
 import com.persagy.common.constant.SaasCommonConstant;
@@ -25,7 +26,6 @@ import com.persagy.security.util.BouncycastleCipher;
 import com.persagy.security.util.SecureAES;
 
 import cn.hutool.core.util.BooleanUtil;
-import cn.hutool.core.util.IdUtil;
 import cn.hutool.crypto.digest.DigestAlgorithm;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -42,7 +42,8 @@ import io.swagger.annotations.ApiOperation;
 @RequestMapping(value = "/authCenter", method = RequestMethod.POST)
 public class SaasAuthCenterController {
 	
-	private static final String SAAS_CLIENT_ID_REDIS_KEY = "SAAS_PLATFORM_CLIENT_ID_KEY";
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
 	
 	@Autowired
 	private ApplicationProperties properties;
@@ -59,20 +60,10 @@ public class SaasAuthCenterController {
     @ApiOperation(value = "申请授权码")
     @RequestMapping(value = "code")
     public ResponseResult getCode(@RequestBody @Validated SaasCodeVO model) {
-    	// 验证客户端ID是否存在
-    	Boolean member = this.redisTemplate.opsForSet().isMember(SAAS_CLIENT_ID_REDIS_KEY, model.getClientId());
-    	if (!BooleanUtil.isTrue(member)) {
-    		return ResponseResultUtil.errorResult(ResponseCode.A0001.getCode(), ResponseCode.A0001.getDesc());
-		}
-    	// 验证是否授权码已存在
-    	String fastSimpleUUID = IdUtil.fastSimpleUUID();
-    	Boolean setIfAbsent = this.redisTemplate.opsForValue().setIfAbsent(model.getClientId() + "_CODE", fastSimpleUUID, 60000L, TimeUnit.MILLISECONDS);
-    	if (!BooleanUtil.isTrue(setIfAbsent)) {
-    		return ResponseResultUtil.errorResult(ResponseCode.A0302.getCode(), ResponseCode.A0001.getDesc());
-		}
-    	Map<String, String> code = new HashedMap<String, String>();
-    	code.put("code", fastSimpleUUID);
-    	return ResponseResultUtil.successResult(code);
+    	String code = this.saasAuthHandler.getCode(model.getClientId(), model.getRedirectUrl());
+    	Map<String, String> result = new HashedMap<String, String>(1);
+    	result.put("code", code);
+    	return ResponseResultUtil.successResult(result);
     }
     
     /**
@@ -83,7 +74,7 @@ public class SaasAuthCenterController {
     @RequestMapping(value = "codeToken")
     public ResponseResult getCodeToken(@RequestBody @Validated SaasCodeTokenVO model) throws UnsupportedEncodingException {
     	// 验证客户端ID是否存在
-    	Boolean member = this.redisTemplate.opsForSet().isMember(SAAS_CLIENT_ID_REDIS_KEY, model.getClientId());
+    	Boolean member = this.redisTemplate.opsForSet().isMember(SaasCommonConstant.SAAS_CLIENT_ID_REDIS_KEY, model.getClientId());
     	if (!BooleanUtil.isTrue(member)) {
     		return ResponseResultUtil.errorResult(ResponseCode.A0001.getCode(), ResponseCode.A0001.getDesc());
 		}

+ 62 - 9
saas-account/src/main/java/com/persagy/account/controller/SaasLoginController.java

@@ -1,6 +1,9 @@
 package com.persagy.account.controller;
 
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -21,14 +24,8 @@ import org.springframework.web.bind.annotation.RestController;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.persagy.common.constant.SaasCommonConstant;
-import com.persagy.common.enums.ResponseCode;
-import com.persagy.common.exception.BusinessException;
-import com.persagy.common.utils.ResponseResult;
-import com.persagy.common.utils.ResponseResultUtil;
-import com.persagy.common.utils.StringUtil;
-import com.persagy.log.core.util.RequestUtil;
 import com.persagy.account.config.ApplicationProperties;
+import com.persagy.account.manage.SaasAuthHandler;
 import com.persagy.account.manage.SaasRoleMenuHandler;
 import com.persagy.account.pojo.dto.SaasAccount;
 import com.persagy.account.pojo.dto.SaasGroup;
@@ -38,6 +35,13 @@ import com.persagy.account.pojo.vo.account.SaasAccountQueryVO;
 import com.persagy.account.pojo.vo.menu.SaasMenuQueryVO;
 import com.persagy.account.service.ISaasAccountService;
 import com.persagy.account.service.ISaasGroupService;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.log.core.util.RequestUtil;
 import com.persagy.security.constant.CipherConstans;
 import com.persagy.security.util.BouncycastleCipher;
 import com.persagy.security.util.SecureAES;
@@ -62,6 +66,12 @@ import lombok.extern.slf4j.Slf4j;
 @RestController
 public class SaasLoginController {
 
+	private static final String HTTP_PREFIX = "http://";
+	private static final String HTTPS_PREFIX = "https://";
+	
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
 	@Autowired
 	private ApplicationProperties properties;
 	
@@ -83,12 +93,14 @@ public class SaasLoginController {
     /**
      * 运维系统账号登录
      * 
-     * @throws UnsupportedEncodingException 
      * @throws NumberFormatException 
+     * @throws IOException 
      */
     @ApiOperation(value = "运维系统账号登录")
     @RequestMapping(value = "saas/login", method = RequestMethod.POST)
-    public ResponseResult saasAccountLogin(@RequestBody @Validated SaasAccountLoginVO loginVO, HttpServletRequest request, HttpServletResponse response) throws NumberFormatException, UnsupportedEncodingException {
+    public ResponseResult saasAccountLogin(@RequestBody @Validated SaasAccountLoginVO loginVO, HttpServletRequest request, HttpServletResponse response) throws NumberFormatException, IOException {
+    	String redirectUrl = this.validSaasSSO(loginVO);
+    	
     	LambdaQueryWrapper<SaasAccount> queryWrapper = new SaasAccount.Builder().createQueryWrapper().usernameEq(loginVO.getUsername()).passwordEq(loginVO.getPassword()).builderQueryWrapper();
     	List<SaasAccount> accounts = this.saasAccountService.list(queryWrapper);
     	if (CollectionUtil.isEmpty(accounts) || accounts.size() > 1) {
@@ -138,6 +150,14 @@ public class SaasLoginController {
     	}
     	account.setAppId(loginVO.getAppId());
     	String token = this.setRedisToken(account, loginVO.getAppId(), loginVO.isRemember(), false);
+    	// 判断是否需要重定向
+    	if (StringUtil.isNotBlank(redirectUrl)) {
+    		String code = this.saasAuthHandler.getCode(loginVO.getClientId(), loginVO.getRedirectUrl());
+			redirectUrl = redirectUrl + "&code=" + code;
+			Map<String, String> temp = new HashMap<String, String>();
+			temp.put("redirectUrl", redirectUrl);
+			return ResponseResultUtil.successResult(temp);
+		}
     	response.setHeader(CipherConstans.TOKEN_HEADER_TOKEN, token);
     	return ResponseResultUtil.successResult(account);
     }
@@ -223,6 +243,39 @@ public class SaasLoginController {
     }
     
     /**
+     * 验证是否需要重定向
+     * @param loginVO
+     * @return 为空时,说明不需要
+     * @throws UnsupportedEncodingException 
+     */
+    private String validSaasSSO(SaasAccountLoginVO loginVO) throws UnsupportedEncodingException {
+    	String state = loginVO.getState();
+    	String clientId = loginVO.getClientId();
+    	String redirectUrl = loginVO.getRedirectUrl();
+    	if (StringUtil.isAllBlank(state, clientId, redirectUrl)) {
+			return null;
+		}
+    	if (StringUtil.isBlank(clientId)) {
+			throw new BusinessException(ResponseCode.A0402.getCode(), "客户端ID,不可为空");
+		}
+    	if (StringUtil.isBlank(redirectUrl)) {
+			throw new BusinessException(ResponseCode.A0402.getCode(), "重定向URL,不可为空");
+		}
+    	// 验证clientId,是否存在
+    	// 验证redirectUrl的有效性
+    	if (redirectUrl.indexOf(HTTP_PREFIX) >= 0 || redirectUrl.indexOf(HTTPS_PREFIX) >= 0) {
+    		redirectUrl = URLEncoder.encode(redirectUrl, StandardCharsets.UTF_8.name());
+    		if (redirectUrl.indexOf("?") > 0) {
+    			redirectUrl = redirectUrl + "&clientId=" + clientId + "&state=" + state;
+			} else {
+				redirectUrl = redirectUrl + "?clientId=" + clientId + "&state=" + state;
+			}
+    		return redirectUrl;
+		}
+    	throw new BusinessException(ResponseCode.A0402.getCode(), "重定向URL,格式错误");
+    }
+    
+    /**
      * 获取此账号的菜单权限树
      * 
      * @param account

+ 51 - 3
saas-account/src/main/java/com/persagy/account/manage/SaasAuthHandler.java

@@ -3,20 +3,27 @@ package com.persagy.account.manage;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.google.common.collect.Lists;
-import com.persagy.common.constant.SaasCommonConstant;
-import com.persagy.common.exception.BusinessException;
-import com.persagy.common.utils.StringUtil;
 import com.persagy.account.pojo.dto.SaasAccount;
 import com.persagy.account.pojo.dto.SaasArea;
 import com.persagy.account.pojo.dto.SaasGroup;
 import com.persagy.account.service.ISaasAccountService;
 import com.persagy.account.service.ISaasGroupService;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.utils.StringUtil;
+
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.crypto.digest.MD5;
 
 /**
  * @version 
@@ -28,6 +35,8 @@ import com.persagy.account.service.ISaasGroupService;
 @Component
 public class SaasAuthHandler {
 	
+	private static MD5 md5 = MD5.create();
+	
     @Autowired
     private ISaasGroupService saasGroupService;
 
@@ -37,6 +46,9 @@ public class SaasAuthHandler {
     @Autowired
     private SaasAreaProjectHandler saasAreaProjectHandler;
     
+	@Autowired
+	private RedisTemplate<String, Object> redisTemplate;
+    
     /**
      * 验证此账号的集团项目权限
      * 
@@ -194,4 +206,40 @@ public class SaasAuthHandler {
 		return result;
     }
     
+    
+    /**
+     * 申请授权码
+     */
+    public String getCode(String clientId, String redirectUrl) {
+    	// 验证客户端ID是否存在
+    	Boolean member = this.redisTemplate.opsForSet().isMember(SaasCommonConstant.SAAS_CLIENT_ID_REDIS_KEY, clientId);
+    	if (!BooleanUtil.isTrue(member)) {
+    		throw new BusinessException(ResponseCode.A0001.getCode(), "非法客户端");
+		}
+    	// 生成新的授权码,并验证授权码是否已存在
+    	String redisKey = this.getCodeRediskey(clientId, redirectUrl);
+    	JSONObject temp = new JSONObject();
+    	temp.put("time", System.currentTimeMillis());
+    	temp.put("redirectUrl", redirectUrl);
+    	String code = md5.digestHex(temp.toJSONString());
+    	Boolean setIfAbsent = this.redisTemplate.opsForValue().setIfAbsent(redisKey, code, 300000L, TimeUnit.MILLISECONDS);
+    	if (!BooleanUtil.isTrue(setIfAbsent)) {
+    		throw new BusinessException(ResponseCode.A0302.getCode(), ResponseCode.A0302.getDesc());
+		}
+    	return code;
+    }
+    
+    /**
+     * 客户端ID
+     * @param clientId 不可为空
+     * @param redirectUrl 可为空
+     * @return
+     */
+    public String getCodeRediskey(String clientId, String redirectUrl) {
+    	if (StringUtil.isBlank(redirectUrl)) {
+    		redirectUrl = "";
+		}
+    	return clientId + SaasCommonConstant.UNDERLINE_JOIN_SYMBOL + md5.digestHex(redirectUrl);
+    }
+    
 }

+ 9 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/account/SaasAccountLoginVO.java

@@ -38,6 +38,15 @@ public class SaasAccountLoginVO {
 	@ApiModelProperty(value = "手机号", example = "WD")
 	private String phone; // 手机号
 	
+	@ApiModelProperty(value = "重定向URL", example = "http://127.0.0.1:8080/test")
+	private String redirectUrl;	// 重定向URL
+
+	@ApiModelProperty(value = "客户端ID", example = "sdfguvhwoign")
+	private String clientId;
+	
+	@ApiModelProperty(value = "客户端状态信息", example = "123")
+	private String state;
+	
 	//@NotBlank(message = "登录密码,不可为空")
 	@ApiModelProperty(value = "是否获取此账号对应的菜单权限树,true-获取,默认false", example = "false")
 	private boolean auths; // 是否获取此账号对应的菜单权限树,true-获取,默认false,选填

+ 3 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/thirty/SaasCodeVO.java

@@ -26,4 +26,7 @@ public class SaasCodeVO {
 	@ApiModelProperty(value = "客户端ID", required = true, example = "13546545")
 	private String clientId; 	// 客户端ID
 	
+	@ApiModelProperty(value = "重定向URL", example = "http://127.0.0.1:8080/test")
+	private String redirectUrl;	// 重定向URL
+	
 }

+ 3 - 1
saas-common/src/main/java/com/persagy/common/constant/SaasCommonConstant.java

@@ -63,6 +63,8 @@ public interface SaasCommonConstant {
 	String SAAS_ROLE_ID_PREFIX = "RO";
 	
 	// 账号来源
-	String ACCOUNT_SOURCE_PERSAGE = "persagy";
+	String ACCOUNT_SOURCE_PERSAGE = "100";	// 100-saas
 
+	String SAAS_CLIENT_ID_REDIS_KEY = "SAAS_PLATFORM_CLIENT_ID_KEY";
+	
 }