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 @@