فهرست منبع

:heavy_plus_sign: 增加验证码校验、增加CaptchaTokenGranter

smallchill 6 سال پیش
والد
کامیت
b338d5ca96

+ 4 - 0
doc/sql/update/common-update-2.3.0~2.3.1.sql

@@ -0,0 +1,4 @@
+-- ----------------------------
+-- 增加验证码授权类型
+-- ----------------------------
+update blade_client set authorized_grant_types = 'refresh_token,password,authorization_code,captcha';

+ 5 - 0
pom.xml

@@ -114,6 +114,11 @@
             <artifactId>blade-core-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>com.github.whvcse</groupId>
+            <artifactId>easy-captcha</artifactId>
+        </dependency>
         <!-- 工作流 -->
         <dependency>
             <groupId>org.flowable</groupId>

+ 1 - 1
src/main/java/org/springblade/common/cache/CacheNames.java

@@ -23,6 +23,6 @@ package org.springblade.common.cache;
  */
 public interface CacheNames {
 
-	String NOTICE_ONE = "notice:one";
+	String CAPTCHA_KEY = "blade:auth::blade:captcha:";
 
 }

+ 18 - 4
src/main/java/org/springblade/modules/auth/controller/AuthController.java

@@ -17,12 +17,15 @@
 package org.springblade.modules.auth.controller;
 
 import com.github.xiaoymin.knife4j.annotations.ApiSort;
+import com.wf.captcha.SpecCaptcha;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
+import org.springblade.common.cache.CacheNames;
 import org.springblade.core.launch.constant.AppConstant;
 import org.springblade.core.log.annotation.ApiLog;
+import org.springblade.core.redis.cache.BladeRedisCache;
 import org.springblade.core.tool.support.Kv;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.WebUtil;
@@ -31,12 +34,11 @@ import org.springblade.modules.auth.granter.TokenGranterBuilder;
 import org.springblade.modules.auth.granter.TokenParameter;
 import org.springblade.modules.auth.utils.TokenUtil;
 import org.springblade.modules.system.entity.UserInfo;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
+import java.time.Duration;
+import java.util.UUID;
 
 /**
  * 认证模块
@@ -50,6 +52,8 @@ import javax.servlet.http.HttpServletResponse;
 @Api(value = "用户授权认证", tags = "授权接口")
 public class AuthController {
 
+	private BladeRedisCache redisCache;
+
 	@ApiLog("登录用户验证")
 	@PostMapping("/oauth/token")
 	@ApiOperation(value = "获取认证token", notes = "传入租户ID:tenantId,账号:account,密码:password")
@@ -81,5 +85,15 @@ public class AuthController {
 		return TokenUtil.createAuthInfo(userInfo);
 	}
 
+	@GetMapping("/oauth/captcha")
+	public Kv captcha() {
+		SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
+		String verCode = specCaptcha.text().toLowerCase();
+		String key = UUID.randomUUID().toString();
+		// 存入redis并设置过期时间为30分钟
+		redisCache.setEx(CacheNames.CAPTCHA_KEY + key, verCode, Duration.ofMinutes(30));
+		// 将key和base64返回给前端
+		return Kv.create().set("key", key).set("image", specCaptcha.toBase64());
+	}
 
 }

+ 89 - 0
src/main/java/org/springblade/modules/auth/granter/CaptchaTokenGranter.java

@@ -0,0 +1,89 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.modules.auth.granter;
+
+import lombok.AllArgsConstructor;
+import org.springblade.common.cache.CacheNames;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.redis.cache.BladeRedisCache;
+import org.springblade.core.tool.utils.DigestUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.core.tool.utils.WebUtil;
+import org.springblade.modules.auth.enums.BladeUserEnum;
+import org.springblade.modules.auth.utils.TokenUtil;
+import org.springblade.modules.system.entity.Tenant;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springblade.modules.system.service.ITenantService;
+import org.springblade.modules.system.service.IUserService;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 验证码TokenGranter
+ *
+ * @author Chill
+ */
+@Component
+@AllArgsConstructor
+public class CaptchaTokenGranter implements ITokenGranter {
+
+	public static final String GRANT_TYPE = "captcha";
+
+	private IUserService userService;
+	private ITenantService tenantService;
+	private BladeRedisCache redisCache;
+
+	@Override
+	public UserInfo grant(TokenParameter tokenParameter) {
+		HttpServletRequest request = WebUtil.getRequest();
+
+		String key = request.getHeader(TokenUtil.CAPTCHA_HEADER_KEY);
+		String code = request.getHeader(TokenUtil.CAPTCHA_HEADER_CODE);
+		// 获取验证码
+		String redisCode = redisCache.get(CacheNames.CAPTCHA_KEY + key);
+		// 判断验证码
+		if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
+			throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
+		}
+
+		String tenantId = tokenParameter.getArgs().getStr("tenantId");
+		String username = tokenParameter.getArgs().getStr("username");
+		String password = tokenParameter.getArgs().getStr("password");
+		UserInfo userInfo = null;
+		if (Func.isNoneBlank(username, password)) {
+			// 获取租户信息
+			Tenant tenant = tenantService.getByTenantId(tenantId);
+			if (!TokenUtil.judgeTenant(tenant)) {
+				throw new ServiceException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
+			}
+			// 获取用户类型
+			String userType = tokenParameter.getArgs().getStr("userType");
+			// 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
+			if (userType.equals(BladeUserEnum.WEB.getName())) {
+				userInfo = userService.userInfo(tenantId, username, DigestUtil.encrypt(password));
+			} else if (userType.equals(BladeUserEnum.APP.getName())) {
+				userInfo = userService.userInfo(tenantId, username, DigestUtil.encrypt(password));
+			} else {
+				userInfo = userService.userInfo(tenantId, username, DigestUtil.encrypt(password));
+			}
+		}
+		return userInfo;
+	}
+
+}

+ 2 - 1
src/main/java/org/springblade/modules/auth/granter/TokenGranterBuilder.java

@@ -33,12 +33,13 @@ import java.util.concurrent.ConcurrentHashMap;
 public class TokenGranterBuilder {
 
 	/**
-	 * TokenGranter缓存池
+	 * TokenGranter缓存池
 	 */
 	private static Map<String, ITokenGranter> granterPool = new ConcurrentHashMap<>();
 
 	static {
 		granterPool.put(PasswordTokenGranter.GRANT_TYPE, SpringUtil.getBean(PasswordTokenGranter.class));
+		granterPool.put(CaptchaTokenGranter.GRANT_TYPE, SpringUtil.getBean(CaptchaTokenGranter.class));
 		granterPool.put(RefreshTokenGranter.GRANT_TYPE, SpringUtil.getBean(RefreshTokenGranter.class));
 	}
 

+ 3 - 0
src/main/java/org/springblade/modules/auth/utils/TokenUtil.java

@@ -39,6 +39,9 @@ import java.util.Map;
  */
 public class TokenUtil {
 
+	public final static String CAPTCHA_HEADER_KEY = "Captcha-Key";
+	public final static String CAPTCHA_HEADER_CODE = "Captcha-Code";
+	public final static String CAPTCHA_NOT_CORRECT = "验证码不正确";
 	public final static String TENANT_HEADER_KEY = "Tenant-Id";
 	public final static String DEFAULT_TENANT_ID = "000000";
 	public final static String USER_TYPE_HEADER_KEY = "User-Type";