Просмотр исходного кода

用户管理:支持在线维护系统用户

xuxueli 6 лет назад
Родитель
Сommit
0a3542dcac

+ 8 - 24
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java Просмотреть файл

1
 package com.xxl.job.admin.controller;
1
 package com.xxl.job.admin.controller;
2
 
2
 
3
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
3
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
4
-import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
5
-import com.xxl.job.admin.core.util.I18nUtil;
4
+import com.xxl.job.admin.service.LoginService;
6
 import com.xxl.job.admin.service.XxlJobService;
5
 import com.xxl.job.admin.service.XxlJobService;
7
 import com.xxl.job.core.biz.model.ReturnT;
6
 import com.xxl.job.core.biz.model.ReturnT;
8
 import org.springframework.beans.propertyeditors.CustomDateEditor;
7
 import org.springframework.beans.propertyeditors.CustomDateEditor;
30
 
29
 
31
 	@Resource
30
 	@Resource
32
 	private XxlJobService xxlJobService;
31
 	private XxlJobService xxlJobService;
32
+	@Resource
33
+	private LoginService loginService;
34
+
33
 
35
 
34
 	@RequestMapping("/")
36
 	@RequestMapping("/")
35
 	public String index(Model model) {
37
 	public String index(Model model) {
49
 	
51
 	
50
 	@RequestMapping("/toLogin")
52
 	@RequestMapping("/toLogin")
51
 	@PermessionLimit(limit=false)
53
 	@PermessionLimit(limit=false)
52
-	public String toLogin(Model model, HttpServletRequest request) {
53
-		if (PermissionInterceptor.ifLogin(request)) {
54
+	public String toLogin(HttpServletRequest request, HttpServletResponse response) {
55
+		if (loginService.ifLogin(request, response) != null) {
54
 			return "redirect:/";
56
 			return "redirect:/";
55
 		}
57
 		}
56
 		return "login";
58
 		return "login";
60
 	@ResponseBody
62
 	@ResponseBody
61
 	@PermessionLimit(limit=false)
63
 	@PermessionLimit(limit=false)
62
 	public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
64
 	public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
63
-		// valid
64
-		if (PermissionInterceptor.ifLogin(request)) {
65
-			return ReturnT.SUCCESS;
66
-		}
67
-
68
-		// param
69
-		if (userName==null || userName.trim().length()==0 || password==null || password.trim().length()==0){
70
-			return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
71
-		}
72
 		boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
65
 		boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
73
-
74
-		// do login
75
-		boolean loginRet = PermissionInterceptor.login(response, userName, password, ifRem);
76
-		if (!loginRet) {
77
-			return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
78
-		}
79
-		return ReturnT.SUCCESS;
66
+		return loginService.login(request, response, userName, password, ifRem);
80
 	}
67
 	}
81
 	
68
 	
82
 	@RequestMapping(value="logout", method=RequestMethod.POST)
69
 	@RequestMapping(value="logout", method=RequestMethod.POST)
83
 	@ResponseBody
70
 	@ResponseBody
84
 	@PermessionLimit(limit=false)
71
 	@PermessionLimit(limit=false)
85
 	public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
72
 	public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
86
-		if (PermissionInterceptor.ifLogin(request)) {
87
-			PermissionInterceptor.logout(request, response);
88
-		}
89
-		return ReturnT.SUCCESS;
73
+		return loginService.logout(request, response);
90
 	}
74
 	}
91
 	
75
 	
92
 	@RequestMapping("/help")
76
 	@RequestMapping("/help")

+ 50 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java Просмотреть файл

1
 package com.xxl.job.admin.controller;
1
 package com.xxl.job.admin.controller;
2
 
2
 
3
+import com.xxl.job.admin.controller.annotation.PermessionLimit;
3
 import com.xxl.job.admin.core.model.XxlJobGroup;
4
 import com.xxl.job.admin.core.model.XxlJobGroup;
4
 import com.xxl.job.admin.core.model.XxlJobUser;
5
 import com.xxl.job.admin.core.model.XxlJobUser;
5
 import com.xxl.job.admin.core.util.I18nUtil;
6
 import com.xxl.job.admin.core.util.I18nUtil;
6
 import com.xxl.job.admin.dao.XxlJobGroupDao;
7
 import com.xxl.job.admin.dao.XxlJobGroupDao;
7
 import com.xxl.job.admin.dao.XxlJobUserDao;
8
 import com.xxl.job.admin.dao.XxlJobUserDao;
9
+import com.xxl.job.admin.service.LoginService;
8
 import com.xxl.job.core.biz.model.ReturnT;
10
 import com.xxl.job.core.biz.model.ReturnT;
9
 import org.springframework.stereotype.Controller;
11
 import org.springframework.stereotype.Controller;
10
 import org.springframework.ui.Model;
12
 import org.springframework.ui.Model;
15
 import org.springframework.web.bind.annotation.ResponseBody;
17
 import org.springframework.web.bind.annotation.ResponseBody;
16
 
18
 
17
 import javax.annotation.Resource;
19
 import javax.annotation.Resource;
20
+import javax.servlet.http.HttpServletRequest;
18
 import java.util.HashMap;
21
 import java.util.HashMap;
19
 import java.util.List;
22
 import java.util.List;
20
 import java.util.Map;
23
 import java.util.Map;
32
     private XxlJobGroupDao xxlJobGroupDao;
35
     private XxlJobGroupDao xxlJobGroupDao;
33
 
36
 
34
     @RequestMapping
37
     @RequestMapping
38
+    @PermessionLimit(adminuser = true)
35
     public String index(Model model) {
39
     public String index(Model model) {
36
 
40
 
37
         // 执行器列表
41
         // 执行器列表
43
 
47
 
44
     @RequestMapping("/pageList")
48
     @RequestMapping("/pageList")
45
     @ResponseBody
49
     @ResponseBody
50
+    @PermessionLimit(adminuser = true)
46
     public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
51
     public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
47
                                         @RequestParam(required = false, defaultValue = "10") int length,
52
                                         @RequestParam(required = false, defaultValue = "10") int length,
48
                                         String username) {
53
                                         String username) {
61
 
66
 
62
     @RequestMapping("/add")
67
     @RequestMapping("/add")
63
     @ResponseBody
68
     @ResponseBody
69
+    @PermessionLimit(adminuser = true)
64
     public ReturnT<String> add(XxlJobUser xxlJobUser) {
70
     public ReturnT<String> add(XxlJobUser xxlJobUser) {
65
 
71
 
66
         // valid username
72
         // valid username
95
 
101
 
96
     @RequestMapping("/update")
102
     @RequestMapping("/update")
97
     @ResponseBody
103
     @ResponseBody
98
-    public ReturnT<String> update(XxlJobUser xxlJobUser) {
104
+    @PermessionLimit(adminuser = true)
105
+    public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {
106
+
107
+        // avoid opt login seft
108
+        XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
109
+        if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
110
+            return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
111
+        }
99
 
112
 
100
         // valid password
113
         // valid password
101
         if (StringUtils.hasText(xxlJobUser.getPassword())) {
114
         if (StringUtils.hasText(xxlJobUser.getPassword())) {
116
 
129
 
117
     @RequestMapping("/remove")
130
     @RequestMapping("/remove")
118
     @ResponseBody
131
     @ResponseBody
119
-    public ReturnT<String> remove(int id) {
132
+    @PermessionLimit(adminuser = true)
133
+    public ReturnT<String> remove(HttpServletRequest request, int id) {
134
+
135
+        // avoid opt login seft
136
+        XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
137
+        if (loginUser.getId() == id) {
138
+            return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
139
+        }
140
+
120
         xxlJobUserDao.delete(id);
141
         xxlJobUserDao.delete(id);
121
         return ReturnT.SUCCESS;
142
         return ReturnT.SUCCESS;
122
     }
143
     }
123
 
144
 
145
+    @RequestMapping("/updatePwd")
146
+    @ResponseBody
147
+    public ReturnT<String> updatePwd(HttpServletRequest request, String password){
148
+
149
+        // valid password
150
+        if (password==null || password.trim().length()==0){
151
+            return new ReturnT<String>(ReturnT.FAIL.getCode(), "密码不可为空");
152
+        }
153
+        password = password.trim();
154
+        if (!(password.length()>=4 && password.length()<=20)) {
155
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
156
+        }
157
+
158
+        // md5 password
159
+        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
160
+
161
+        // update pwd
162
+        XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
163
+
164
+        // do write
165
+        XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername());
166
+        existUser.setPassword(md5Password);
167
+        xxlJobUserDao.update(existUser);
168
+
169
+        return ReturnT.SUCCESS;
170
+    }
171
+
124
 }
172
 }

+ 7 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermessionLimit.java Просмотреть файл

19
 	 */
19
 	 */
20
 	boolean limit() default true;
20
 	boolean limit() default true;
21
 
21
 
22
+	/**
23
+	 * 要求管理员权限
24
+	 *
25
+	 * @return
26
+	 */
27
+	boolean adminuser() default false;
28
+
22
 }
29
 }

+ 26 - 54
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java Просмотреть файл

1
 package com.xxl.job.admin.controller.interceptor;
1
 package com.xxl.job.admin.controller.interceptor;
2
 
2
 
3
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
3
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
4
-import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
5
-import com.xxl.job.admin.core.util.CookieUtil;
4
+import com.xxl.job.admin.core.model.XxlJobUser;
5
+import com.xxl.job.admin.core.util.I18nUtil;
6
+import com.xxl.job.admin.service.LoginService;
6
 import org.springframework.stereotype.Component;
7
 import org.springframework.stereotype.Component;
7
-import org.springframework.util.DigestUtils;
8
 import org.springframework.web.method.HandlerMethod;
8
 import org.springframework.web.method.HandlerMethod;
9
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
9
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
10
 
10
 
11
+import javax.annotation.Resource;
11
 import javax.servlet.http.HttpServletRequest;
12
 import javax.servlet.http.HttpServletRequest;
12
 import javax.servlet.http.HttpServletResponse;
13
 import javax.servlet.http.HttpServletResponse;
13
-import java.math.BigInteger;
14
 
14
 
15
 /**
15
 /**
16
- * 权限拦截, 简易版
16
+ * 权限拦截
17
  *
17
  *
18
  * @author xuxueli 2015-12-12 18:09:04
18
  * @author xuxueli 2015-12-12 18:09:04
19
  */
19
  */
20
 @Component
20
 @Component
21
 public class PermissionInterceptor extends HandlerInterceptorAdapter {
21
 public class PermissionInterceptor extends HandlerInterceptorAdapter {
22
 
22
 
23
-
24
-	public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
25
-	private static String LOGIN_IDENTITY_TOKEN;
26
-	public static String getLoginIdentityToken() {
27
-		if (LOGIN_IDENTITY_TOKEN == null) {
28
-			String username = XxlJobAdminConfig.getAdminConfig().getLoginUsername();
29
-			String password = XxlJobAdminConfig.getAdminConfig().getLoginPassword();
30
-
31
-			// login token
32
-			String tokenTmp = DigestUtils.md5DigestAsHex(String.valueOf(username + "_" + password).getBytes());		//.getBytes("UTF-8")
33
-			tokenTmp = new BigInteger(1, tokenTmp.getBytes()).toString(16);
34
-
35
-			LOGIN_IDENTITY_TOKEN = tokenTmp;
36
-		}
37
-		return LOGIN_IDENTITY_TOKEN;
38
-	}
39
-
40
-	public static boolean login(HttpServletResponse response, String username, String password, boolean ifRemember){
41
-
42
-    	// login token
43
-		String tokenTmp = DigestUtils.md5DigestAsHex(String.valueOf(username + "_" + password).getBytes());
44
-		tokenTmp = new BigInteger(1, tokenTmp.getBytes()).toString(16);
45
-
46
-		if (!getLoginIdentityToken().equals(tokenTmp)){
47
-			return false;
48
-		}
49
-
50
-		// do login
51
-		CookieUtil.set(response, LOGIN_IDENTITY_KEY, getLoginIdentityToken(), ifRemember);
52
-		return true;
53
-	}
54
-	public static void logout(HttpServletRequest request, HttpServletResponse response){
55
-		CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
56
-	}
57
-	public static boolean ifLogin(HttpServletRequest request){
58
-		String indentityInfo = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
59
-		if (indentityInfo==null || !getLoginIdentityToken().equals(indentityInfo.trim())) {
60
-			return false;
61
-		}
62
-		return true;
63
-	}
64
-
65
-
23
+	@Resource
24
+	private LoginService loginService;
66
 
25
 
67
 	@Override
26
 	@Override
68
 	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
27
 	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
70
 		if (!(handler instanceof HandlerMethod)) {
29
 		if (!(handler instanceof HandlerMethod)) {
71
 			return super.preHandle(request, response, handler);
30
 			return super.preHandle(request, response, handler);
72
 		}
31
 		}
73
-		
74
-		if (!ifLogin(request)) {
75
-			HandlerMethod method = (HandlerMethod)handler;
76
-			PermessionLimit permission = method.getMethodAnnotation(PermessionLimit.class);
77
-			if (permission == null || permission.limit()) {
32
+
33
+		// if need login
34
+		boolean needLogin = true;
35
+		boolean needAdminuser = false;
36
+		HandlerMethod method = (HandlerMethod)handler;
37
+		PermessionLimit permission = method.getMethodAnnotation(PermessionLimit.class);
38
+		if (permission!=null) {
39
+			needLogin = permission.limit();
40
+			needAdminuser = permission.adminuser();
41
+		}
42
+
43
+		if (needLogin) {
44
+			XxlJobUser loginUser = loginService.ifLogin(request, response);
45
+			if (loginUser == null) {
78
 				response.sendRedirect(request.getContextPath() + "/toLogin");
46
 				response.sendRedirect(request.getContextPath() + "/toLogin");
79
 				//request.getRequestDispatcher("/toLogin").forward(request, response);
47
 				//request.getRequestDispatcher("/toLogin").forward(request, response);
80
 				return false;
48
 				return false;
81
 			}
49
 			}
50
+			if (needAdminuser && loginUser.getRole()!=1) {
51
+				throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
52
+			}
53
+			request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
82
 		}
54
 		}
83
-		
55
+
84
 		return super.preHandle(request, response, handler);
56
 		return super.preHandle(request, response, handler);
85
 	}
57
 	}
86
 	
58
 	

+ 0 - 14
xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java Просмотреть файл

30
     }
30
     }
31
 
31
 
32
     // conf
32
     // conf
33
-
34
-    @Value("${xxl.job.login.username}")
35
-    private String loginUsername;
36
-
37
-    @Value("${xxl.job.login.password}")
38
-    private String loginPassword;
39
-
40
     @Value("${xxl.job.i18n}")
33
     @Value("${xxl.job.i18n}")
41
     private String i18n;
34
     private String i18n;
42
 
35
 
61
     @Resource
54
     @Resource
62
     private JavaMailSender mailSender;
55
     private JavaMailSender mailSender;
63
 
56
 
64
-    public String getLoginUsername() {
65
-        return loginUsername;
66
-    }
67
-
68
-    public String getLoginPassword() {
69
-        return loginPassword;
70
-    }
71
 
57
 
72
     public String getI18n() {
58
     public String getI18n() {
73
         return i18n;
59
         return i18n;

+ 107 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java Просмотреть файл

1
+package com.xxl.job.admin.service;
2
+
3
+import com.xxl.job.admin.core.model.XxlJobUser;
4
+import com.xxl.job.admin.core.util.CookieUtil;
5
+import com.xxl.job.admin.core.util.I18nUtil;
6
+import com.xxl.job.admin.core.util.JacksonUtil;
7
+import com.xxl.job.admin.dao.XxlJobUserDao;
8
+import com.xxl.job.core.biz.model.ReturnT;
9
+import org.springframework.context.annotation.Configuration;
10
+import org.springframework.util.DigestUtils;
11
+
12
+import javax.annotation.Resource;
13
+import javax.servlet.http.HttpServletRequest;
14
+import javax.servlet.http.HttpServletResponse;
15
+import java.math.BigInteger;
16
+
17
+/**
18
+ * @author xuxueli 2019-05-04 22:13:264
19
+ */
20
+@Configuration
21
+public class LoginService {
22
+
23
+    public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
24
+
25
+    @Resource
26
+    private XxlJobUserDao xxlJobUserDao;
27
+
28
+
29
+    private String makeToken(XxlJobUser xxlJobUser){
30
+        String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
31
+        String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
32
+        return tokenHex;
33
+    }
34
+    private XxlJobUser parseToken(String tokenHex){
35
+        XxlJobUser xxlJobUser = null;
36
+        if (tokenHex != null) {
37
+            String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray());      // username_password(md5)
38
+            xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class);
39
+        }
40
+        return xxlJobUser;
41
+    }
42
+
43
+
44
+    public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){
45
+
46
+        // param
47
+        if (username==null || username.trim().length()==0 || password==null || password.trim().length()==0){
48
+            return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
49
+        }
50
+
51
+        // valid passowrd
52
+        XxlJobUser xxlJobUser = xxlJobUserDao.loadByUserName(username);
53
+        if (xxlJobUser == null) {
54
+            return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
55
+        }
56
+        String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes());
57
+        if (!passwordMd5.equals(xxlJobUser.getPassword())) {
58
+            return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
59
+        }
60
+
61
+        String loginToken = makeToken(xxlJobUser);
62
+
63
+        // do login
64
+        CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember);
65
+        return ReturnT.SUCCESS;
66
+    }
67
+
68
+    /**
69
+     * logout
70
+     *
71
+     * @param request
72
+     * @param response
73
+     */
74
+    public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
75
+        CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
76
+        return ReturnT.SUCCESS;
77
+    }
78
+
79
+    /**
80
+     * logout
81
+     *
82
+     * @param request
83
+     * @return
84
+     */
85
+    public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){
86
+        String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
87
+        if (cookieToken != null) {
88
+            XxlJobUser cookieUser = null;
89
+            try {
90
+                cookieUser = parseToken(cookieToken);
91
+            } catch (Exception e) {
92
+                logout(request, response);
93
+            }
94
+            if (cookieUser != null) {
95
+                XxlJobUser dbUser = xxlJobUserDao.loadByUserName(cookieUser.getUsername());
96
+                if (dbUser != null) {
97
+                    if (cookieUser.getPassword().equals(dbUser.getPassword())) {
98
+                        return dbUser;
99
+                    }
100
+                }
101
+            }
102
+        }
103
+        return null;
104
+    }
105
+
106
+
107
+}

+ 3 - 0
xxl-job-admin/src/main/resources/i18n/message.properties Просмотреть файл

32
 system_nav=导航
32
 system_nav=导航
33
 system_digits=整数
33
 system_digits=整数
34
 system_lengh_limit=长度限制
34
 system_lengh_limit=长度限制
35
+system_permission_limit=权限拦截
35
 
36
 
36
 ## daterangepicker
37
 ## daterangepicker
37
 daterangepicker_ranges_recent_hour=最近一小时
38
 daterangepicker_ranges_recent_hour=最近一小时
241
 user_add=新增用户
242
 user_add=新增用户
242
 user_update=更新用户
243
 user_update=更新用户
243
 user_username_repeat=账号重复
244
 user_username_repeat=账号重复
245
+user_username_valid=限制以小写字母开头,由小写字母、数字组成
244
 user_password_update_placeholder=请输入新密码,为空则不更新密码
246
 user_password_update_placeholder=请输入新密码,为空则不更新密码
247
+user_update_loginuser_limit=禁止操作当前登录账号
245
 
248
 
246
 ## help
249
 ## help
247
 job_help=使用教程
250
 job_help=使用教程

+ 3 - 0
xxl-job-admin/src/main/resources/i18n/message_en.properties Просмотреть файл

32
 system_nav=Navigation
32
 system_nav=Navigation
33
 system_digits=digits
33
 system_digits=digits
34
 system_lengh_limit=Length limit
34
 system_lengh_limit=Length limit
35
+system_permission_limit=Permission limit
35
 
36
 
36
 ## daterangepicker
37
 ## daterangepicker
37
 daterangepicker_ranges_recent_hour=recent one hour
38
 daterangepicker_ranges_recent_hour=recent one hour
241
 user_add=Add User
242
 user_add=Add User
242
 user_update=Edit User
243
 user_update=Edit User
243
 user_username_repeat=Username Repeat
244
 user_username_repeat=Username Repeat
245
+user_username_valid=Restrictions start with a lowercase letter and consist of lowercase letters and Numbers
244
 user_password_update_placeholder=Please input password, empty means not update
246
 user_password_update_placeholder=Please input password, empty means not update
247
+user_update_loginuser_limit=Operation of current login account is not allowed
245
 
248
 
246
 ## help
249
 ## help
247
 job_help=Tutorial
250
 job_help=Tutorial

+ 64 - 0
xxl-job-admin/src/main/resources/static/js/common.1.js Просмотреть файл

88
 	 	$('body').addClass('sidebar-collapse');
88
 	 	$('body').addClass('sidebar-collapse');
89
 	 }
89
 	 }
90
 	 */
90
 	 */
91
+
92
+
93
+    // update pwd
94
+    $('#updatePwd').on('click', function(){
95
+        $('#updatePwdModal').modal({backdrop: false, keyboard: false}).modal('show');
96
+    });
97
+    var updatePwdModalValidate = $("#updatePwdModal .form").validate({
98
+        errorElement : 'span',
99
+        errorClass : 'help-block',
100
+        focusInvalid : true,
101
+        rules : {
102
+            password : {
103
+                required : true ,
104
+                rangelength:[4,50]
105
+            }
106
+        },
107
+        messages : {
108
+            password : {
109
+                required : '请输入密码'  ,
110
+                rangelength : "密码长度限制为4~50"
111
+            }
112
+        },
113
+        highlight : function(element) {
114
+            $(element).closest('.form-group').addClass('has-error');
115
+        },
116
+        success : function(label) {
117
+            label.closest('.form-group').removeClass('has-error');
118
+            label.remove();
119
+        },
120
+        errorPlacement : function(error, element) {
121
+            element.parent('div').append(error);
122
+        },
123
+        submitHandler : function(form) {
124
+            $.post(base_url + "/user/updatePwd",  $("#updatePwdModal .form").serialize(), function(data, status) {
125
+                if (data.code == 200) {
126
+                    $('#updatePwdModal').modal('hide');
127
+
128
+                    layer.msg( '修改密码成功,即将注销登陆' );
129
+                    setTimeout(function(){
130
+                        $.post(base_url + "/logout", function(data, status) {
131
+                            if (data.code == 200) {
132
+                                window.location.href = base_url + "/";
133
+                            } else {
134
+                                layer.open({
135
+                                    icon: '2',
136
+                                    content: (data.msg||'注销失败')
137
+                                });
138
+                            }
139
+                        });
140
+                    }, 500);
141
+                } else {
142
+                    layer.open({
143
+                        icon: '2',
144
+                        content: (data.msg||'修改密码失败')
145
+                    });
146
+                }
147
+            });
148
+        }
149
+    });
150
+    $("#updatePwdModal").on('hide.bs.modal', function () {
151
+        $("#updatePwdModal .form")[0].reset();
152
+        updatePwdModalValidate.resetForm();
153
+        $("#updatePwdModal .form .form-group").removeClass("has-error");
154
+    });
91
 	
155
 	
92
 });
156
 });

+ 9 - 2
xxl-job-admin/src/main/resources/static/js/user.index.1.js Просмотреть файл

50
 	                {
50
 	                {
51
 	                	"data": 'permission',
51
 	                	"data": 'permission',
52
 						"width":'10%',
52
 						"width":'10%',
53
-	                	"visible" : true
53
+	                	"visible" : false
54
 	                },
54
 	                },
55
 	                {
55
 	                {
56
 						"data": I18n.system_opt ,
56
 						"data": I18n.system_opt ,
144
         $("#addModal .form input[name='permission']").prop("checked",false);
144
         $("#addModal .form input[name='permission']").prop("checked",false);
145
     });
145
     });
146
 
146
 
147
+    jQuery.validator.addMethod("myValid01", function(value, element) {
148
+        var length = value.length;
149
+        var valid = /^[a-z][a-z0-9]*$/;
150
+        return this.optional(element) || valid.test(value);
151
+    }, I18n.user_username_valid );
152
+
147
 	// add
153
 	// add
148
 	$(".add").click(function(){
154
 	$(".add").click(function(){
149
 		$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
155
 		$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
155
         rules : {
161
         rules : {
156
             username : {
162
             username : {
157
 				required : true,
163
 				required : true,
158
-                rangelength:[4, 20]
164
+                rangelength:[4, 20],
165
+                myValid01: true
159
 			},
166
 			},
160
             password : {
167
             password : {
161
                 required : true,
168
                 required : true,

+ 43 - 6
xxl-job-admin/src/main/resources/templates/common/common.macro.ftl Просмотреть файл

49
     <script src="${request.contextPath}/static/adminlte/bower_components/PACE/pace.min.js"></script>
49
     <script src="${request.contextPath}/static/adminlte/bower_components/PACE/pace.min.js"></script>
50
     <#-- jquery cookie -->
50
     <#-- jquery cookie -->
51
 	<script src="${request.contextPath}/static/plugins/jquery/jquery.cookie.js"></script>
51
 	<script src="${request.contextPath}/static/plugins/jquery/jquery.cookie.js"></script>
52
+	<#-- jquery.validate -->
53
+	<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
52
 
54
 
53
 	<#-- layer -->
55
 	<#-- layer -->
54
 	<script src="${request.contextPath}/static/plugins/layer/layer.js"></script>
56
 	<script src="${request.contextPath}/static/plugins/layer/layer.js"></script>
79
 
81
 
80
           	<div class="navbar-custom-menu">
82
           	<div class="navbar-custom-menu">
81
 				<ul class="nav navbar-nav">
83
 				<ul class="nav navbar-nav">
82
-					<li class="dropdown user user-menu">
83
-	                    <a href=";" id="logoutBtn" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
84
-                      		<span class="hidden-xs">${I18n.logout_btn}</span>
85
-	                    </a>
86
-					</li>
84
+					<#-- login user -->
85
+                    <li class="dropdown">
86
+                        <a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
87
+                            欢迎 ${Request["XXL_JOB_LOGIN_IDENTITY"].username}
88
+                            <span class="caret"></span>
89
+                        </a>
90
+                        <ul class="dropdown-menu" role="menu">
91
+                            <li id="updatePwd" ><a href="javascript:">修改密码</a></li>
92
+                            <li id="logoutBtn" ><a href="javascript:">${I18n.logout_btn}</a></li>
93
+                        </ul>
94
+                    </li>
87
 				</ul>
95
 				</ul>
88
 			</div>
96
 			</div>
89
 
97
 
90
 		</nav>
98
 		</nav>
91
 	</header>
99
 	</header>
100
+
101
+	<!-- 修改密码.模态框 -->
102
+	<div class="modal fade" id="updatePwdModal" tabindex="-1" role="dialog"  aria-hidden="true">
103
+		<div class="modal-dialog ">
104
+			<div class="modal-content">
105
+				<div class="modal-header">
106
+					<h4 class="modal-title" >修改密码</h4>
107
+				</div>
108
+				<div class="modal-body">
109
+					<form class="form-horizontal form" role="form" >
110
+						<div class="form-group">
111
+							<label for="lastname" class="col-sm-2 control-label">新密码<font color="red">*</font></label>
112
+							<div class="col-sm-10"><input type="text" class="form-control" name="password" placeholder="请输入新密码" maxlength="100" ></div>
113
+						</div>
114
+						<hr>
115
+						<div class="form-group">
116
+							<div class="col-sm-offset-3 col-sm-6">
117
+								<button type="submit" class="btn btn-primary"  >保存</button>
118
+								<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
119
+							</div>
120
+						</div>
121
+					</form>
122
+				</div>
123
+			</div>
124
+		</div>
125
+	</div>
126
+
92
 </#macro>
127
 </#macro>
93
 
128
 
94
 <#macro commonLeft pageName >
129
 <#macro commonLeft pageName >
103
 				<li class="nav-click <#if pageName == "jobinfo">active</#if>" ><a href="${request.contextPath}/jobinfo"><i class="fa fa-circle-o text-yellow"></i><span>${I18n.jobinfo_name}</span></a></li>
138
 				<li class="nav-click <#if pageName == "jobinfo">active</#if>" ><a href="${request.contextPath}/jobinfo"><i class="fa fa-circle-o text-yellow"></i><span>${I18n.jobinfo_name}</span></a></li>
104
 				<li class="nav-click <#if pageName == "joblog">active</#if>" ><a href="${request.contextPath}/joblog"><i class="fa fa-circle-o text-green"></i><span>${I18n.joblog_name}</span></a></li>
139
 				<li class="nav-click <#if pageName == "joblog">active</#if>" ><a href="${request.contextPath}/joblog"><i class="fa fa-circle-o text-green"></i><span>${I18n.joblog_name}</span></a></li>
105
                 <li class="nav-click <#if pageName == "jobgroup">active</#if>" ><a href="${request.contextPath}/jobgroup"><i class="fa fa-circle-o text-red"></i><span>${I18n.jobgroup_name}</span></a></li>
140
                 <li class="nav-click <#if pageName == "jobgroup">active</#if>" ><a href="${request.contextPath}/jobgroup"><i class="fa fa-circle-o text-red"></i><span>${I18n.jobgroup_name}</span></a></li>
106
-                <li class="nav-click <#if pageName == "user">active</#if>" ><a href="${request.contextPath}/user"><i class="fa fa-circle-o text-purple"></i><span>${I18n.user_manage}</span></a></li>
141
+				<#if Request["XXL_JOB_LOGIN_IDENTITY"].role == 1>
142
+                    <li class="nav-click <#if pageName == "user">active</#if>" ><a href="${request.contextPath}/user"><i class="fa fa-circle-o text-purple"></i><span>${I18n.user_manage}</span></a></li>
143
+				</#if>
107
 				<li class="nav-click <#if pageName == "help">active</#if>" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-gray"></i><span>${I18n.job_help}</span></a></li>
144
 				<li class="nav-click <#if pageName == "help">active</#if>" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-gray"></i><span>${I18n.job_help}</span></a></li>
108
 			</ul>
145
 			</ul>
109
 		</section>
146
 		</section>

+ 0 - 2
xxl-job-admin/src/main/resources/templates/jobgroup/jobgroup.index.ftl Просмотреть файл

194
 <!-- DataTables -->
194
 <!-- DataTables -->
195
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
195
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
196
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
196
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
197
-<#-- jquery.validate -->
198
-<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
199
 <script src="${request.contextPath}/static/js/jobgroup.index.1.js"></script>
197
 <script src="${request.contextPath}/static/js/jobgroup.index.1.js"></script>
200
 </body>
198
 </body>
201
 </html>
199
 </html>

+ 0 - 1
xxl-job-admin/src/main/resources/templates/jobinfo/jobinfo.index.ftl Просмотреть файл

413
 <!-- DataTables -->
413
 <!-- DataTables -->
414
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
414
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
415
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
415
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
416
-<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
417
 <!-- moment -->
416
 <!-- moment -->
418
 <script src="${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js"></script>
417
 <script src="${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js"></script>
419
 <script src="${request.contextPath}/static/js/jobinfo.index.1.js"></script>
418
 <script src="${request.contextPath}/static/js/jobinfo.index.1.js"></script>

+ 0 - 1
xxl-job-admin/src/main/resources/templates/login.ftl Просмотреть файл

38
 		</form>
38
 		</form>
39
 	</div>
39
 	</div>
40
 <@netCommon.commonScript />
40
 <@netCommon.commonScript />
41
-<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
42
 <script src="${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js"></script>
41
 <script src="${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js"></script>
43
 <script src="${request.contextPath}/static/js/login.1.js"></script>
42
 <script src="${request.contextPath}/static/js/login.1.js"></script>
44
 
43
 

+ 0 - 1
xxl-job-admin/src/main/resources/templates/user/user.index.ftl Просмотреть файл

173
 <!-- DataTables -->
173
 <!-- DataTables -->
174
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
174
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
175
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
175
 <script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
176
-<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
177
 <script src="${request.contextPath}/static/js/user.index.1.js"></script>
176
 <script src="${request.contextPath}/static/js/user.index.1.js"></script>
178
 </body>
177
 </body>
179
 </html>
178
 </html>

+ 4 - 5
xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java Просмотреть файл

1
 package com.xxl.job.admin.controller;
1
 package com.xxl.job.admin.controller;
2
 
2
 
3
-import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
4
-import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
3
+import com.xxl.job.admin.service.LoginService;
5
 import org.junit.Before;
4
 import org.junit.Before;
6
 import org.junit.Test;
5
 import org.junit.Test;
7
 import org.springframework.http.MediaType;
6
 import org.springframework.http.MediaType;
22
     MvcResult ret = mockMvc.perform(
21
     MvcResult ret = mockMvc.perform(
23
         post("/login")
22
         post("/login")
24
             .contentType(MediaType.APPLICATION_FORM_URLENCODED)
23
             .contentType(MediaType.APPLICATION_FORM_URLENCODED)
25
-            .param("userName", XxlJobAdminConfig.getAdminConfig().getLoginUsername())
26
-            .param("password", XxlJobAdminConfig.getAdminConfig().getLoginPassword())
24
+            .param("userName", "admin")
25
+            .param("password", "123456")
27
     ).andReturn();
26
     ).andReturn();
28
-    cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY);
27
+    cookie = ret.getResponse().getCookie(LoginService.LOGIN_IDENTITY_KEY);
29
   }
28
   }
30
 
29
 
31
   @Test
30
   @Test