From 679117d53b391db501e134cbae0c2adbac190cdb Mon Sep 17 00:00:00 2001 From: linlinjava Date: Sun, 27 Dec 2020 14:38:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litemall-admin-api/pom.xml | 4 ++ .../litemall/admin/config/KaptchaConfig.java | 31 ++++++++++++ .../litemall/admin/config/ShiroConfig.java | 1 + .../admin/shiro/AdminWebSessionManager.java | 2 +- .../admin/util/AdminResponseCode.java | 2 + .../admin/web/AdminAuthController.java | 50 ++++++++++++++++++- litemall-admin/src/api/login.js | 11 +++- litemall-admin/src/store/modules/user.js | 2 +- litemall-admin/src/utils/request.js | 2 + litemall-admin/src/views/login/index.vue | 34 ++++++++++++- .../litemall/core/config/CorsConfig.java | 1 + .../litemall/core/util/ResponseUtil.java | 8 +++ pom.xml | 8 ++- 13 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/KaptchaConfig.java diff --git a/litemall-admin-api/pom.xml b/litemall-admin-api/pom.xml index 5afd40cc..5e7f2757 100644 --- a/litemall-admin-api/pom.xml +++ b/litemall-admin-api/pom.xml @@ -40,6 +40,10 @@ org.apache.shiro shiro-spring-boot-web-starter + + com.github.penggle + kaptcha + com.github.xiaoymin swagger-bootstrap-ui diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/KaptchaConfig.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/KaptchaConfig.java new file mode 100644 index 00000000..3dad229d --- /dev/null +++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/KaptchaConfig.java @@ -0,0 +1,31 @@ +package org.linlinjava.litemall.admin.config; + +import com.google.code.kaptcha.Producer; +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +@Configuration +public class KaptchaConfig { + + @Bean + public Producer kaptchaProducer() { + Properties properties = new Properties(); + properties.setProperty("kaptcha.image.width", "100"); + properties.setProperty("kaptcha.image.height", "40"); + properties.setProperty("kaptcha.textproducer.font.size", "32"); + properties.setProperty("kaptcha.textproducer.font.color", "0,0,0"); + properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYAZ"); + properties.setProperty("kaptcha.textproducer.char.length", "4"); + properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); + + DefaultKaptcha kaptcha = new DefaultKaptcha(); + Config config = new Config(properties); + kaptcha.setConfig(config); + return kaptcha; + } + +} \ No newline at end of file diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/ShiroConfig.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/ShiroConfig.java index 18b9b257..9ef972f5 100644 --- a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/ShiroConfig.java +++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/ShiroConfig.java @@ -29,6 +29,7 @@ public class ShiroConfig { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map filterChainDefinitionMap = new LinkedHashMap(); + filterChainDefinitionMap.put("/admin/auth/kaptcha", "anon"); filterChainDefinitionMap.put("/admin/auth/login", "anon"); filterChainDefinitionMap.put("/admin/auth/401", "anon"); filterChainDefinitionMap.put("/admin/auth/index", "anon"); diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/shiro/AdminWebSessionManager.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/shiro/AdminWebSessionManager.java index d9c784d9..3234a62f 100644 --- a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/shiro/AdminWebSessionManager.java +++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/shiro/AdminWebSessionManager.java @@ -18,7 +18,7 @@ public class AdminWebSessionManager extends DefaultWebSessionManager { public AdminWebSessionManager() { super(); setGlobalSessionTimeout(MILLIS_PER_HOUR * 6); - setSessionIdCookieEnabled(false); +// setSessionIdCookieEnabled(false); setSessionIdUrlRewritingEnabled(false); } diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/AdminResponseCode.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/AdminResponseCode.java index 6a0ff0ac..8d7a0207 100644 --- a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/AdminResponseCode.java +++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/AdminResponseCode.java @@ -7,6 +7,8 @@ public class AdminResponseCode { public static final Integer ADMIN_ALTER_NOT_ALLOWED = 603; public static final Integer ADMIN_DELETE_NOT_ALLOWED = 604; public static final Integer ADMIN_INVALID_ACCOUNT = 605; + public static final Integer ADMIN_INVALID_KAPTCHA = 606; + public static final Integer ADMIN_INVALID_KAPTCHA_REQUIRED = 607; public static final Integer GOODS_UPDATE_NOT_ALLOWED = 610; public static final Integer GOODS_NAME_EXIST = 611; public static final Integer ORDER_CONFIRM_NOT_ALLOWED = 620; diff --git a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAuthController.java b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAuthController.java index 59becab5..506d61a4 100644 --- a/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAuthController.java +++ b/litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAuthController.java @@ -1,5 +1,6 @@ package org.linlinjava.litemall.admin.web; +import com.google.code.kaptcha.Producer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.shiro.SecurityUtils; @@ -24,12 +25,18 @@ import org.springframework.context.ApplicationContext; import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import sun.misc.BASE64Encoder; +import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.time.LocalDateTime; import java.util.*; -import static org.linlinjava.litemall.admin.util.AdminResponseCode.ADMIN_INVALID_ACCOUNT; +import static org.linlinjava.litemall.admin.util.AdminResponseCode.*; @RestController @RequestMapping("/admin/auth") @@ -46,6 +53,37 @@ public class AdminAuthController { @Autowired private LogHelper logHelper; + @Autowired + private Producer kaptchaProducer; + + @GetMapping("/kaptcha") + public Object kaptcha(HttpServletRequest request) { + String kaptcha = doKaptcha(request); + if (kaptcha != null) { + return ResponseUtil.ok(kaptcha); + } + return ResponseUtil.fail(); + } + + private String doKaptcha(HttpServletRequest request) { + // 生成验证码 + String text = kaptchaProducer.createText(); + BufferedImage image = kaptchaProducer.createImage(text); + HttpSession session = request.getSession(); + session.setAttribute("kaptcha", text); + + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ImageIO.write(image, "jpeg", outputStream); + BASE64Encoder encoder = new BASE64Encoder(); + String base64 = encoder.encode(outputStream.toByteArray()); + String captchaBase64 = "data:image/jpeg;base64," + base64.replaceAll("\r\n", ""); + return captchaBase64; + } catch (IOException e) { + return null; + } + } + /* * { username : value, password : value } */ @@ -53,10 +91,20 @@ public class AdminAuthController { public Object login(@RequestBody String body, HttpServletRequest request) { String username = JacksonUtil.parseString(body, "username"); String password = JacksonUtil.parseString(body, "password"); + String code = JacksonUtil.parseString(body, "code"); if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { return ResponseUtil.badArgument(); } + if (StringUtils.isEmpty(code)) { + return ResponseUtil.fail(ADMIN_INVALID_KAPTCHA_REQUIRED, "验证码不能空"); + } + + HttpSession session = request.getSession(); + String kaptcha = (String)session.getAttribute("kaptcha"); + if (Objects.requireNonNull(code).compareToIgnoreCase(kaptcha) != 0) { + return ResponseUtil.fail(ADMIN_INVALID_KAPTCHA, "验证码不正确", doKaptcha(request)); + } Subject currentUser = SecurityUtils.getSubject(); try { diff --git a/litemall-admin/src/api/login.js b/litemall-admin/src/api/login.js index 2d2261ad..dccd73ae 100644 --- a/litemall-admin/src/api/login.js +++ b/litemall-admin/src/api/login.js @@ -1,9 +1,10 @@ import request from '@/utils/request' -export function loginByUsername(username, password) { +export function loginByUsername(username, password, code) { const data = { username, - password + password, + code } return request({ url: '/auth/login', @@ -27,3 +28,9 @@ export function getUserInfo(token) { }) } +export function getKaptcha() { + return request({ + url: '/auth/kaptcha', + method: 'get' + }) +} diff --git a/litemall-admin/src/store/modules/user.js b/litemall-admin/src/store/modules/user.js index 6fb68688..13cf1412 100644 --- a/litemall-admin/src/store/modules/user.js +++ b/litemall-admin/src/store/modules/user.js @@ -35,7 +35,7 @@ const user = { LoginByUsername({ commit }, userInfo) { const username = userInfo.username.trim() return new Promise((resolve, reject) => { - loginByUsername(username, userInfo.password).then(response => { + loginByUsername(username, userInfo.password, userInfo.code).then(response => { const token = response.data.data.token commit('SET_TOKEN', token) setToken(token) diff --git a/litemall-admin/src/utils/request.js b/litemall-admin/src/utils/request.js index 4b9085f3..147329f6 100644 --- a/litemall-admin/src/utils/request.js +++ b/litemall-admin/src/utils/request.js @@ -3,6 +3,8 @@ import { Message, MessageBox } from 'element-ui' import store from '@/store' import { getToken } from '@/utils/auth' +axios.defaults.withCredentials = true + // create an axios instance const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url diff --git a/litemall-admin/src/views/login/index.vue b/litemall-admin/src/views/login/index.vue index 7e357137..cf2cf93a 100644 --- a/litemall-admin/src/views/login/index.vue +++ b/litemall-admin/src/views/login/index.vue @@ -18,6 +18,16 @@ + + + + + + + + 登录
@@ -43,6 +53,8 @@