Commit 4f8f35ef054588d426e9b21285a31730000449cd

Authored by 潘钊
1 parent 07456ef2

重写登录模块

@@ -180,6 +180,11 @@ @@ -180,6 +180,11 @@
180 <version>1.4.7</version> 180 <version>1.4.7</version>
181 </dependency> 181 </dependency>
182 182
  183 + <dependency>
  184 + <groupId>com.github.axet</groupId>
  185 + <artifactId>kaptcha</artifactId>
  186 + <version>0.0.9</version>
  187 + </dependency>
183 </dependencies> 188 </dependencies>
184 189
185 <dependencyManagement> 190 <dependencyManagement>
src/main/java/com/bsth/common/Constants.java
@@ -13,12 +13,13 @@ public class Constants { @@ -13,12 +13,13 @@ public class Constants {
13 /** 13 /**
14 * 不需要拦截的资源 14 * 不需要拦截的资源
15 */ 15 */
16 - public static final String LOGIN = "/login"; 16 + public static final String LOGIN = "/user/login/**";
17 public static final String LOGIN_PAGE = "/login.html"; 17 public static final String LOGIN_PAGE = "/login.html";
18 public static final String ASSETS_URL = "/assets/**"; 18 public static final String ASSETS_URL = "/assets/**";
19 public static final String FAVICON_URL = "/favicon.ico"; 19 public static final String FAVICON_URL = "/favicon.ico";
20 public static final String METRONIC_URL = "/metronic_v4.5.4/**"; 20 public static final String METRONIC_URL = "/metronic_v4.5.4/**";
21 public static final String LOGIN_FAILURE = "/user/loginFailure"; 21 public static final String LOGIN_FAILURE = "/user/loginFailure";
  22 + public static final String CAPTCHA = "/captcha.jpg";
22 23
23 /** 24 /**
24 * 线调部分子页面不做拦截,便于浏览器缓存 25 * 线调部分子页面不做拦截,便于浏览器缓存
src/main/java/com/bsth/controller/sys/UserController.java
1 package com.bsth.controller.sys; 1 package com.bsth.controller.sys;
2 2
  3 +import java.util.HashMap;
  4 +import java.util.Map;
  5 +
3 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletRequest;
4 import javax.servlet.http.HttpSession; 7 import javax.servlet.http.HttpSession;
5 8
  9 +import org.apache.commons.lang3.StringUtils;
  10 +import org.apache.commons.net.util.Base64;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
6 import org.springframework.beans.factory.annotation.Autowired; 13 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.security.authentication.BadCredentialsException; 14 import org.springframework.security.authentication.BadCredentialsException;
8 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 15 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
9 import org.springframework.security.web.authentication.session.SessionAuthenticationException; 16 import org.springframework.security.web.authentication.session.SessionAuthenticationException;
10 import org.springframework.web.bind.annotation.RequestMapping; 17 import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RequestMethod;
11 import org.springframework.web.bind.annotation.RequestParam; 19 import org.springframework.web.bind.annotation.RequestParam;
12 import org.springframework.web.bind.annotation.RestController; 20 import org.springframework.web.bind.annotation.RestController;
13 21
  22 +import com.bsth.common.Constants;
  23 +import com.bsth.common.ResponseCode;
14 import com.bsth.controller.BaseController; 24 import com.bsth.controller.BaseController;
15 import com.bsth.entity.sys.SysUser; 25 import com.bsth.entity.sys.SysUser;
16 import com.bsth.security.util.SecurityUtils; 26 import com.bsth.security.util.SecurityUtils;
@@ -18,75 +28,158 @@ import com.bsth.service.sys.SysUserService; @@ -18,75 +28,158 @@ import com.bsth.service.sys.SysUserService;
18 28
19 @RestController 29 @RestController
20 @RequestMapping("user") 30 @RequestMapping("user")
21 -public class UserController extends BaseController<SysUser, Integer>{  
22 - 31 +public class UserController extends BaseController<SysUser, Integer> {
  32 +
  33 + Logger logger = LoggerFactory.getLogger(this.getClass());
  34 +
23 @Autowired 35 @Autowired
24 SysUserService sysUserService; 36 SysUserService sysUserService;
25 37
  38 + //需要验证码的账号
  39 + public static Map<String, Integer> captchaMap = new HashMap<>();
  40 +
  41 + @RequestMapping(value = "/login", method = RequestMethod.POST)
  42 + public Map<String, Object> login(HttpServletRequest request, @RequestParam String userName,
  43 + @RequestParam String password) {
  44 + Map<String, Object> rs = new HashMap<>();
  45 + rs.put("status", ResponseCode.ERROR);
  46 + try {
  47 + HttpSession session = request.getSession();
  48 + rs.put("captcha", session.getAttribute("captcha"));
  49 +
  50 + if(captchaMap.get(userName) != null && captchaMap.get(userName) >= 3){
  51 + //校验验证码
  52 + String verCode = (String) session
  53 + .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
  54 + String captcha = request.getParameter("captcha");
  55 +
  56 + if(StringUtils.isBlank(captcha)){
  57 + rs.put("msg", "请输入验证码");
  58 + return rs;
  59 + }
  60 +
  61 + if(!verCode.equals(captcha)){
  62 + rs.put("msg", "验证码有误,请刷新后重新输入");
  63 + return rs;
  64 + }
  65 + }
  66 +
  67 + SysUser user = sysUserService.findByUserName(userName);
  68 + if (null == user) {
  69 + rs.put("msg", "不存在的用户");
  70 + return rs;
  71 + }
  72 +
  73 + if (!user.isEnabled()) {
  74 + rs.put("msg", "该用户已被锁定,请联系管理员");
  75 + return rs;
  76 + }
  77 +
  78 + // 校验密码
  79 + password = fourDecodeBase64(password);
  80 + boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
  81 + if (!matchStatus) {
  82 + rs.put("msg", "密码有误");
  83 +
  84 + Integer captchSize = captchaMap.get(userName);
  85 + if(null == captchSize)
  86 + captchSize = 0;
  87 +
  88 + captchSize ++;
  89 + captchaMap.put(userName, captchSize);
  90 + return rs;
  91 + }
  92 +
  93 + // 登录
  94 + SecurityUtils.login(user, request);
  95 + //session里写入用户名,webSocket连接时标识身份用
  96 + session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
  97 +
  98 + captchaMap.remove(userName);
  99 + rs.put("status", ResponseCode.SUCCESS);
  100 + } catch (Exception e) {
  101 + logger.error("", e);
  102 + rs.put("msg", "服务器出现异常,请联系管理员");
  103 + }
  104 + return rs;
  105 + }
  106 +
  107 + @RequestMapping(value = "/login/captchaStatus")
  108 + public int captchaStatus(String userName){
  109 + Integer size = captchaMap.get(userName);
  110 + return size == null?0:size;
  111 + }
  112 +
  113 + private String fourDecodeBase64(String t) {
  114 + return new String(Base64.decodeBase64(Base64.decodeBase64(Base64.decodeBase64(Base64.decodeBase64(t)))));
  115 + }
  116 +
26 /** 117 /**
27 * 118 *
28 - * @Title: loginFailure  
29 - * @Description: TODO(查询登录失败的详细信息)  
30 - * @param @param request  
31 - * @return String 返回类型  
32 - * @throws 119 + * @Title: loginFailure @Description: TODO(查询登录失败的详细信息) @param @param
  120 + * request @return String 返回类型 @throws
33 */ 121 */
34 @RequestMapping("/loginFailure") 122 @RequestMapping("/loginFailure")
35 - public String loginFailure(HttpServletRequest request){ 123 + public String loginFailure(HttpServletRequest request) {
36 String msg = ""; 124 String msg = "";
37 HttpSession session = request.getSession(); 125 HttpSession session = request.getSession();
38 - 126 +
39 Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION"); 127 Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
40 -  
41 - if(obj instanceof BadCredentialsException) 128 +
  129 + if (obj instanceof BadCredentialsException)
42 msg = "登录失败,用户名或密码错误."; 130 msg = "登录失败,用户名或密码错误.";
43 - else if(obj instanceof SessionAuthenticationException) 131 + else if (obj instanceof SessionAuthenticationException)
44 msg = "登录失败,当前策略不允许重复登录."; 132 msg = "登录失败,当前策略不允许重复登录.";
45 session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION"); 133 session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
46 return msg; 134 return msg;
47 } 135 }
48 - 136 +
49 @RequestMapping("/currentUser") 137 @RequestMapping("/currentUser")
50 - public SysUser currentUser(){ 138 + public SysUser currentUser() {
51 return SecurityUtils.getCurrentUser(); 139 return SecurityUtils.getCurrentUser();
52 } 140 }
53 - 141 +
54 /** 142 /**
55 * @Title changeEnabled 143 * @Title changeEnabled
56 - * @Description: TODO(改变用户状态)  
57 - * @param id 用户ID  
58 - * @param enabled 状态 144 + * @Description: TODO(改变用户状态)
  145 + * @param id
  146 + * 用户ID
  147 + * @param enabled
  148 + * 状态
59 * @return 149 * @return
60 */ 150 */
61 @RequestMapping("/changeEnabled") 151 @RequestMapping("/changeEnabled")
62 - public int changeEnabled(@RequestParam int id,@RequestParam int enabled){  
63 - return sysUserService.changeEnabled(id,enabled); 152 + public int changeEnabled(@RequestParam int id, @RequestParam int enabled) {
  153 + return sysUserService.changeEnabled(id, enabled);
64 } 154 }
65 - 155 +
66 /** 156 /**
67 * @Title changePWD 157 * @Title changePWD
68 - * @Description: TODO(修改密码)  
69 - * @param oldPWD 原始密码  
70 - * @param newwPWD 新密码  
71 - * @param cnewPWD 确认新密码 158 + * @Description: TODO(修改密码)
  159 + * @param oldPWD
  160 + * 原始密码
  161 + * @param newwPWD
  162 + * 新密码
  163 + * @param cnewPWD
  164 + * 确认新密码
72 * @return 165 * @return
73 */ 166 */
74 @RequestMapping("/changePWD") 167 @RequestMapping("/changePWD")
75 - public String changePWD(@RequestParam String oldPWD,@RequestParam String newPWD,@RequestParam String cnewPWD){ 168 + public String changePWD(@RequestParam String oldPWD, @RequestParam String newPWD, @RequestParam String cnewPWD) {
76 SysUser sysUser = SecurityUtils.getCurrentUser(); 169 SysUser sysUser = SecurityUtils.getCurrentUser();
77 String msg = ""; 170 String msg = "";
78 - if(new BCryptPasswordEncoder(4).matches(oldPWD, sysUser.getPassword())){  
79 - if(oldPWD.equals(newPWD)){ 171 + if (new BCryptPasswordEncoder(4).matches(oldPWD, sysUser.getPassword())) {
  172 + if (oldPWD.equals(newPWD)) {
80 msg = "新密码不能跟原始密码一样!"; 173 msg = "新密码不能跟原始密码一样!";
81 - }else{  
82 - if(newPWD.equals(cnewPWD)){  
83 - sysUserService.changePWD(sysUser.getId(),newPWD); 174 + } else {
  175 + if (newPWD.equals(cnewPWD)) {
  176 + sysUserService.changePWD(sysUser.getId(), newPWD);
84 msg = "修改成功!"; 177 msg = "修改成功!";
85 - }else{  
86 - msg= "新密码两次输入不一致!"; 178 + } else {
  179 + msg = "新密码两次输入不一致!";
87 } 180 }
88 } 181 }
89 - }else{ 182 + } else {
90 msg = "原始密码错误!"; 183 msg = "原始密码错误!";
91 } 184 }
92 return msg; 185 return msg;
src/main/java/com/bsth/security/WebSecurityConfig.java
@@ -14,13 +14,11 @@ import org.springframework.security.core.session.SessionRegistryImpl; @@ -14,13 +14,11 @@ import org.springframework.security.core.session.SessionRegistryImpl;
14 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
15 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; 15 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
16 import org.springframework.security.web.authentication.logout.LogoutHandler; 16 import org.springframework.security.web.authentication.logout.LogoutHandler;
17 -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;  
18 import org.springframework.security.web.session.HttpSessionEventPublisher; 17 import org.springframework.security.web.session.HttpSessionEventPublisher;
19 18
20 import com.bsth.common.Constants; 19 import com.bsth.common.Constants;
21 import com.bsth.security.filter.LoginInterceptor; 20 import com.bsth.security.filter.LoginInterceptor;
22 import com.bsth.security.handler.CustomLogoutHandler; 21 import com.bsth.security.handler.CustomLogoutHandler;
23 -import com.bsth.security.handler.LoginSuccessHandler;  
24 22
25 @Configuration 23 @Configuration
26 @EnableWebSecurity 24 @EnableWebSecurity
@@ -39,7 +37,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -39,7 +37,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
39 @Override 37 @Override
40 public void configure(WebSecurity web) throws Exception { 38 public void configure(WebSecurity web) throws Exception {
41 // 白名单 39 // 白名单
42 - web.ignoring().antMatchers(Constants.LOGIN_PAGE, Constants.ASSETS_URL, Constants.FAVICON_URL, 40 + web.ignoring().antMatchers(Constants.LOGIN_PAGE, Constants.LOGIN, Constants.ASSETS_URL, Constants.FAVICON_URL, Constants.CAPTCHA,
43 Constants.METRONIC_URL, Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.XD_TEMPS); 41 Constants.METRONIC_URL, Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.XD_TEMPS);
44 } 42 }
45 43
@@ -58,11 +56,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -58,11 +56,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
58 //指定登录页 56 //指定登录页
59 .loginPage(Constants.LOGIN_PAGE) 57 .loginPage(Constants.LOGIN_PAGE)
60 .loginProcessingUrl(Constants.LOGIN).permitAll() 58 .loginProcessingUrl(Constants.LOGIN).permitAll()
61 - //登录失败跳转的链接  
62 - .failureUrl(Constants.LOGIN_PAGE + "?error=true")  
63 - //登录成功后处理  
64 - .successHandler(loginSuccessHandler())  
65 - //登出 59 + //.failureUrl(Constants.LOGIN_PAGE + "?error=true")登录失败跳转的链接
  60 + //.successHandler(loginSuccessHandler())登录成功后处理
66 .and().logout() 61 .and().logout()
67 .addLogoutHandler(logoutHandler()) 62 .addLogoutHandler(logoutHandler())
68 //禁用CXRF 63 //禁用CXRF
@@ -92,10 +87,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -92,10 +87,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
92 return filterSecurityInterceptor; 87 return filterSecurityInterceptor;
93 } 88 }
94 89
95 - @Bean 90 +/* @Bean
96 public LoginSuccessHandler loginSuccessHandler(){ 91 public LoginSuccessHandler loginSuccessHandler(){
97 return new LoginSuccessHandler(); 92 return new LoginSuccessHandler();
98 - } 93 + }*/
99 94
100 @Bean 95 @Bean
101 public LogoutHandler logoutHandler(){ 96 public LogoutHandler logoutHandler(){
src/main/java/com/bsth/security/handler/LoginSuccessHandler.java
1 -package com.bsth.security.handler;  
2 -  
3 -import java.io.IOException;  
4 -import java.util.Date;  
5 -  
6 -import javax.servlet.ServletException;  
7 -import javax.servlet.http.HttpServletRequest;  
8 -import javax.servlet.http.HttpServletResponse;  
9 -  
10 -import org.springframework.security.core.Authentication;  
11 -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;  
12 -  
13 -import com.bsth.common.Constants;  
14 -import com.bsth.entity.sys.SessionLog;  
15 -import com.bsth.entity.sys.SysUser;  
16 -import com.bsth.util.IpUtils;  
17 -  
18 -public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{  
19 -  
20 - @Override  
21 - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,  
22 - Authentication authentication) throws ServletException, IOException {  
23 -  
24 - SysUser user = (SysUser) authentication.getPrincipal();  
25 -  
26 - //日志  
27 - SessionLog sLog = new SessionLog();  
28 - sLog.setLoginDate(new Date());  
29 - sLog.setUser(user);  
30 - sLog.setIp(IpUtils.getIpAddr(request));  
31 -  
32 - //session里写入用户名  
33 - request.getSession().setAttribute(Constants.SESSION_USERNAME, user.getUserName());  
34 - super.onAuthenticationSuccess(request, response, authentication);  
35 - }  
36 -  
37 -} 1 +//package com.bsth.security.handler;
  2 +//
  3 +//import java.io.IOException;
  4 +//import java.util.Date;
  5 +//
  6 +//import javax.servlet.ServletException;
  7 +//import javax.servlet.http.HttpServletRequest;
  8 +//import javax.servlet.http.HttpServletResponse;
  9 +//
  10 +//import org.springframework.security.core.Authentication;
  11 +//import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
  12 +//
  13 +//import com.bsth.common.Constants;
  14 +//import com.bsth.entity.sys.SessionLog;
  15 +//import com.bsth.entity.sys.SysUser;
  16 +//import com.bsth.util.IpUtils;
  17 +//
  18 +//public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
  19 +//
  20 +// @Override
  21 +// public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
  22 +// Authentication authentication) throws ServletException, IOException {
  23 +//
  24 +// SysUser user = (SysUser) authentication.getPrincipal();
  25 +//
  26 +// //日志
  27 +// SessionLog sLog = new SessionLog();
  28 +// sLog.setLoginDate(new Date());
  29 +// sLog.setUser(user);
  30 +// sLog.setIp(IpUtils.getIpAddr(request));
  31 +//
  32 +// //session里写入用户名
  33 +// request.getSession().setAttribute(Constants.SESSION_USERNAME, user.getUserName());
  34 +// super.onAuthenticationSuccess(request, response, authentication);
  35 +// }
  36 +//
  37 +//}
src/main/java/com/bsth/security/util/SecurityUtils.java
1 package com.bsth.security.util; 1 package com.bsth.security.util;
2 2
  3 +import javax.servlet.http.HttpServletRequest;
  4 +
3 import org.slf4j.Logger; 5 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory; 6 import org.slf4j.LoggerFactory;
  7 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  8 +import org.springframework.security.core.context.SecurityContext;
5 import org.springframework.security.core.context.SecurityContextHolder; 9 import org.springframework.security.core.context.SecurityContextHolder;
6 10
  11 +import com.bsth.entity.sys.SecurityUser;
7 import com.bsth.entity.sys.SysUser; 12 import com.bsth.entity.sys.SysUser;
8 13
9 /** 14 /**
@@ -33,4 +38,12 @@ public class SecurityUtils { @@ -33,4 +38,12 @@ public class SecurityUtils {
33 } 38 }
34 return user; 39 return user;
35 } 40 }
  41 +
  42 + public static void login(SysUser user, HttpServletRequest request){
  43 + SecurityUser securityUser = new SecurityUser(user);
  44 + SecurityContext sContext = SecurityContextHolder.getContext();
  45 + sContext.setAuthentication(
  46 + new UsernamePasswordAuthenticationToken(securityUser, securityUser.getAuthorities()));
  47 + request.getSession(true).setAttribute("SPRING_SECURITY_CONTEXT", sContext);
  48 + }
36 } 49 }
src/main/java/com/bsth/service/sys/impl/ModuleServiceImpl.java
1 package com.bsth.service.sys.impl; 1 package com.bsth.service.sys.impl;
2 2
3 import java.util.ArrayList; 3 import java.util.ArrayList;
4 -import java.util.Collections;  
5 -import java.util.Comparator;  
6 import java.util.HashMap; 4 import java.util.HashMap;
7 import java.util.HashSet; 5 import java.util.HashSet;
8 import java.util.List; 6 import java.util.List;
@@ -82,6 +80,7 @@ public class ModuleServiceImpl extends BaseServiceImpl&lt;Module, Integer&gt; implemen @@ -82,6 +80,7 @@ public class ModuleServiceImpl extends BaseServiceImpl&lt;Module, Integer&gt; implemen
82 searchParentNode(m, map, pSet); 80 searchParentNode(m, map, pSet);
83 } 81 }
84 results.addAll(pSet); 82 results.addAll(pSet);
  83 +
85 return results; 84 return results;
86 } 85 }
87 86
src/main/resources/static/assets/js/common.js
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * success 删除成功之后的回调 5 * success 删除成功之后的回调
6 */ 6 */
7 function removeConfirm(text, url, success) { 7 function removeConfirm(text, url, success) {
8 - layer.confirm(text, { 8 + layer.confirm(html_encode(text), {
9 btn : [ '确定删除', '取消' ], 9 btn : [ '确定删除', '取消' ],
10 icon : 3, 10 icon : 3,
11 skin : 'layui-layer-cfm-delete' 11 skin : 'layui-layer-cfm-delete'
@@ -19,6 +19,19 @@ function removeConfirm(text, url, success) { @@ -19,6 +19,19 @@ function removeConfirm(text, url, success) {
19 }); 19 });
20 } 20 }
21 21
  22 +function html_encode(str) {
  23 + var s = "";
  24 + if (str.length == 0) return "";
  25 +
  26 + s = str.replace(/&/g, "&gt;");
  27 + s = s.replace(/</g, "&lt;");
  28 + s = s.replace(/>/g, "&gt;");
  29 + s = s.replace(/ /g, "&nbsp;");
  30 + s = s.replace(/\'/g, "&#39;");
  31 + s = s.replace(/\"/g, "&quot;");
  32 + return s;
  33 +}
  34 +
22 35
23 function successHandle(json, handle){ 36 function successHandle(json, handle){
24 var status = json.status; 37 var status = json.status;
src/main/resources/static/login.html
@@ -3,152 +3,337 @@ @@ -3,152 +3,337 @@
3 <head> 3 <head>
4 <meta charset="utf-8" /> 4 <meta charset="utf-8" />
5 <title>登录</title> 5 <title>登录</title>
6 -<meta name=”renderer” content=”webkit”>  
7 -<meta http-equiv=”X-UA-Compatible” content=”IE=Edge,chrome=1″>  
8 -<meta content="width=device-width, initial-scale=1" name="viewport" />  
9 -<meta content="" name="description" />  
10 -<meta content="" name="author" />  
11 -<!-- BEGIN GLOBAL MANDATORY STYLES -->  
12 <link 6 <link
13 - href="metronic_v4.5.4/plugins/font-awesome/css/font-awesome.min.css" 7 + href="/metronic_v4.5.4/plugins/font-awesome/css/font-awesome.min.css"
14 rel="stylesheet" type="text/css" /> 8 rel="stylesheet" type="text/css" />
15 -<link href="metronic_v4.5.4/plugins/bootstrap/css/bootstrap.min.css" 9 +<!-- Bootstrap style -->
  10 +<link href="/metronic_v4.5.4/plugins/bootstrap/css/bootstrap.min.css"
16 rel="stylesheet" type="text/css" /> 11 rel="stylesheet" type="text/css" />
17 -<link href="metronic_v4.5.4/css/components.css" rel="stylesheet"  
18 - type="text/css" />  
19 -<link href="metronic_v4.5.4/css/plugins.css" rel="stylesheet"  
20 - type="text/css" />  
21 12
  13 +<!-- METRONIC style -->
  14 +<link href="/metronic_v4.5.4/css/components.css" rel="stylesheet"
  15 + type="text/css" />
  16 +
22 <style type="text/css"> 17 <style type="text/css">
23 -/* Cubic Bezier Transition */  
24 -/***  
25 -Login page  
26 -***/  
27 -/* bg color */  
28 -.login {  
29 - width: 100%;  
30 - height: 100%;  
31 - background-image: url(./assets/img/login_bgbg.png);  
32 - background-size: 100%  
33 -}  
34 -  
35 -.loginCenter {  
36 - background-image: url(./assets/img/login_bgcenter.png);  
37 - background-repeat: no-repeat;  
38 - background-size: 100%;  
39 -  
40 - width: 768px;  
41 - height: 283.2px;  
42 - margin: auto;  
43 - position: absolute;  
44 - top: 0;  
45 - left: 0;  
46 - bottom: 0;  
47 - right: 0;  
48 - 18 +body>.wrapper {
  19 + background-image: url(/assets/img/bg_9b9dcb65ff.png);
  20 + background-size: 100px;
  21 + background-repeat: repeat;
  22 + min-height: 800px;
  23 + min-width: 630px;
  24 + position: absolute;
  25 + top: 0;
  26 + bottom: 0;
  27 + left: 0;
  28 + right: 0;
49 } 29 }
50 30
51 -.loginInputDiv {  
52 - top: 48%;  
53 -/* width: 80%; 31 +#loginPanel.dialog-shadow {
  32 + width: 450px;
  33 + /* height: 400px; */
  34 + border: 1px solid #dadada;
  35 + border-radius: 10px !important;
54 position: absolute; 36 position: absolute;
55 - vertical-align: middle;  
56 - text-align: center; */  
57 -}  
58 -  
59 -/* .loginInput {  
60 - height: 35px;  
61 - padding: 6px 12px;  
62 - background-color: #fff;  
63 - border: 1px solid #c2cad8;  
64 - border-radius: 2px !important;  
65 - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);  
66 - box-shadow: inset 0 1px 1px rgba(0,0,0,.075);  
67 - -webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;  
68 - -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;  
69 - transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;  
70 -} */  
71 -  
72 -.buttonLogin {  
73 - cursor: pointer; 37 + box-shadow: 0 9px 30px -6px rgba(0, 0, 0, .2), 0 18px 20px -10px
  38 + rgba(0, 0, 0, .04), 0 18px 20px -10px rgba(0, 0, 0, .04), 0 10px 20px
  39 + -10px rgba(0, 0, 0, .04);
  40 + background: url(/assets/img/dialog-gray-bg_42c40b3eb6.png) #fff bottom
  41 + repeat-x;
  42 + top: 50%;
  43 + left: 50%;
  44 + margin-left: -225px;
  45 + margin-top: -300px;
  46 + text-align: center;
  47 + color: #333;
  48 + opacity: .5;
  49 +
  50 + padding-bottom: 56px;
  51 +
  52 + animation: to_center 1s forwards;
  53 + animation-delay: .2s;
  54 +
  55 + transition: all .3s ease;
  56 +}
  57 +
  58 +@keyframes to_center
  59 +{
  60 + 0% {margin-top: -300px;opacity: .5;}
  61 + 100% {margin-top: -270px;opacity: 1;}
  62 +}
  63 +
  64 +
  65 +h3 {
  66 + font-size: 25px;
  67 + font-weight: 600;
  68 + color: #4a4a4a
74 } 69 }
75 70
76 -.login-form{  
77 - position: relative; 71 +.input-icon input {
  72 + height: 48px;
  73 + border-radius: 5px !important;
  74 + transition: all .5s ease;
  75 +}
  76 +
  77 +.input-icon input:FOCUS {
  78 + border-color: #c2cad8;
  79 + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
  80 +}
  81 +
  82 +.input-icon>i {
  83 + margin-top: 16px;
  84 +}
  85 +
  86 +#loginPanel #loginBtn.btn{
  87 + border-radius: 6px !important;
  88 + width: 378px;
  89 + height: 48px;
  90 + font-size: 20px;
  91 + font-family: 微软雅黑;
  92 + transition: all .3s ease;
  93 +
  94 + background: #5f7ed7;
  95 + background: linear-gradient(#6f97e5,#527ed9);
  96 + box-shadow: inset 0 1px 2px #7ea1e8 !important;
  97 + color: #fff;
  98 + text-shadow: #4f70b3 0 -1px 0;
  99 + border: none;
  100 +}
  101 +
  102 +#loginPanel #loginBtn.btn:HOVER {
  103 + box-shadow: inset 0 1px 1px #7696de,inset 0 0 2px #627dca,inset 0 -2px 3px #5a77c7,inset 0 0 100px rgba(48,77,147,.4) !important;
  104 +}
  105 +
  106 +
  107 +#loginPanel.show_msg{
  108 + top: calc(50% - 10px);
  109 +}
  110 +
  111 +#loginPanel .alert{
  112 + display: none;
  113 + padding: 12px;
  114 + margin-top: 21px;
  115 + border-radius: 0 0 10px 10px !important;
  116 + font-size: 13px;
  117 +
  118 + position: absolute;
78 width: 100%; 119 width: 100%;
79 - height: 100%;  
80 - text-align: center; 120 + border-bottom: 1px solid #dadada;
  121 +}
  122 +
  123 +#loginPanel .alert.login-success{
  124 + color: #27a4b0;
  125 + background: #abe7ed;
  126 + border-color: #abe7ed;
  127 +}
  128 +
  129 +#loginPanel .alert i{
  130 + font-size: 16px;
  131 + vertical-align: middle;
  132 + margin: 0 5px 3px;
  133 +}
  134 +
  135 +#loginPanel.show_msg .alert{
  136 + display: block;
  137 +}
  138 +
  139 +#captchaWrap{
  140 + display: none;
  141 + text-align: left;
  142 + border-top: 1px solid #f3f2f2;
  143 +}
  144 +
  145 +img.captcha-img{
  146 + cursor: pointer;
81 } 147 }
82 </style> 148 </style>
83 </head> 149 </head>
84 150
85 -<body class="login">  
86 - <div class="loginCenter">  
87 - <form class="login-form" action="/login" method="post">  
88 - <div class="col-md-12 loginInputDiv">  
89 -  
90 - <div class="input-icon right" style="display: inline-block;">  
91 - <i class="fa fa-user"></i>  
92 - <input type="text" class="form-control " placeholder="用户名" name="username" value=""> </div>  
93 - 151 +<body>
  152 + <div class="wrapper ng-scope">
  153 + <div id="loginPanel" class="dialog dialog-shadow">
  154 + <br>
  155 + <h3>闵行公交调度系统 </h3>
  156 + <hr>
  157 + <form style="padding: 0px 35px;">
  158 + <div class="form-group" style="margin-bottom: 0">
  159 + <label></label>
  160 + <div class="input-icon">
  161 + <i class="fa fa-user font-gray"></i> <input type="text" name="userName"
  162 + class="form-control" placeholder="输入用户名" autofocus="autofocus" autocomplete="off">
  163 + </div>
  164 + </div>
94 165
95 - <div class="input-icon right" style="display: inline-block;">  
96 - <i class="fa fa-key"></i>  
97 - <input type="password" class="form-control " placeholder="密码" name="password" value="" > </div>  
98 - &nbsp;&nbsp;  
99 - <button type="submit" class="btn blue buttonLogin" style="border-radius: 5px !important;  
100 - font-family: 微软雅黑;">登&nbsp;录</button> 166 + <div class="form-group">
  167 + <label></label>
  168 + <div class="input-icon">
  169 + <i class="fa fa-key font-gray"></i> <input type="password" name="password"
  170 + class="form-control" placeholder="输入密码" >
  171 + </div>
  172 + </div>
101 173
102 - </div>  
103 - </form> 174 + <div class="form-group" id="captchaWrap">
  175 + <label></label>
  176 + <div class="input-icon">
  177 + <input type="password" name="captcha" style="width: 153px !important;"
  178 + class="form-control input-inline input-medium" placeholder="输入验证码" >
  179 +
  180 + <span class="help-inline"> <img alt="验证码" class="captcha-img" title="点击刷新验证码"> </span>
  181 + </div>
  182 + </div>
  183 + </form>
  184 + <br><br>
  185 + <div class="form-actions" >
  186 + <button type="button" class="btn blue-steel" id="loginBtn" disabled="disabled">登录</button>
  187 + </div>
  188 +
  189 + <div class="alert alert-danger"></div>
  190 + </div>
104 </div> 191 </div>
105 - <script src="metronic_v4.5.4/plugins/jquery.min.js"  
106 - type="text/javascript"></script>  
107 - <script src="metronic_v4.5.4/plugins/bootstrap/js/bootstrap.min.js"  
108 - type="text/javascript"></script>  
109 - <script src="metronic_v4.5.4/scripts/app.min.js" type="text/javascript"></script>  
110 -  
111 - <script src="assets/plugins/purl.js"></script>  
112 -  
113 - <script type="text/javascript">  
114 - $(function() {  
115 - $('input[name=username]').focus();  
116 - /* setCenterCss(); */  
117 - if ($.url().param('error')) {  
118 - //去session里查一下失败信息  
119 - $.get('/user/loginFailure', function(msg) {  
120 - if (msg && msg != '')  
121 - alert(msg);  
122 - location.href = '/login.html';  
123 - }); 192 +
  193 +<!-- jQuery -->
  194 +<script src="/metronic_v4.5.4/plugins/jquery.min.js" ></script>
  195 +<script src="/assets/plugins/jquery.base64.min.js" ></script>
  196 +
  197 +<script>
  198 +!function(){
  199 + var form = $('#loginPanel form')
  200 + ,nameInput = $('input[name=userName]', form)
  201 + ,pwdInput = $('input[name=password]', form)
  202 + ,msgAlert = $('#loginPanel .alert-danger');
  203 +
  204 + $('input', form).on('keyup', checkBtnStatus);
  205 +
  206 + function checkBtnStatus(){
  207 + var es = $('input:visible', form);
  208 + for(var i = 0, e; e = es[i++];){
  209 + if($.trim($(e).val()) == ''){
  210 + $('#loginBtn').attr('disabled', 'disabled');
  211 + $('#loginPanel').removeClass('show_msg');
  212 + return;
  213 + }
  214 + }
  215 + $('#loginBtn').removeAttr('disabled');
  216 + }
  217 +
  218 + nameInput.on('blur', checkStatus);
  219 + //keyup 事件做延迟
  220 + var uNameKeyup;
  221 + nameInput.on('keyup', function(){
  222 + if(uNameKeyup)
  223 + return;
  224 + uNameKeyup = true;
  225 + setTimeout(function(){
  226 + checkStatus();
  227 + uNameKeyup = false;
  228 + }, 200);
  229 + });
  230 +
  231 + //密码框回车事件
  232 + pwdInput.on('keyup', function(e){
  233 + if (e.keyCode == 13)
  234 + $('#loginBtn').click();
  235 + });
  236 + //验证码框回车事件
  237 + $('input[name=captcha]').on('keyup', function(e){
  238 + if (e.keyCode == 13)
  239 + $('#loginBtn').click();
  240 + });
  241 +
  242 + $('#loginBtn').on('click', function(){
  243 + if(lock || $(this).attr('disabled')) return;
  244 + var userName = nameInput.val()
  245 + ,pwd = fourBase64(pwdInput.val());
  246 +
  247 + login(userName, pwd);
  248 + });
  249 +
  250 + var lock;
  251 + function login(userName, pwd){
  252 + lock = true;
  253 + $('#loginBtn').attr('disabled', 'disabled');
  254 + var params = {
  255 + userName: userName,
  256 + password: pwd,
  257 + captcha: $('input[name=captcha]').val()
  258 + };
  259 + $.post('/user/login', params
  260 + ,function(rs){
  261 +
  262 + $('#loginPanel').addClass('show_msg');
  263 + if(error(rs)){
  264 + lock = false;
  265 + $('#loginBtn').removeAttr('disabled');
  266 +
  267 + msgAlert.html('<i class="fa fa-times-circle"> </i> 登录失败,' + rs.msg);
  268 +
  269 + _captcha.refresh();
  270 + checkStatus();
  271 + }
  272 + else{
  273 + msgAlert.html('<i class="fa fa-check"> </i> 登录成功!');
  274 + msgAlert.addClass('login-success');
  275 + window.location.href = '/';
124 } 276 }
125 - /* $(window).resize(setCenterCss); */  
126 - // 设置登录界面样式,让登陆框始终居中  
127 - /* function setCenterCss() {  
128 - $(".loginCenter").css({  
129 - width : $(window).width() * 0.4,  
130 - height : $(window).height() * 0.2,  
131 - });  
132 - $(".loginCenter").css({  
133 - left : ($(window).width() - $(".loginCenter") .outerWidth()) / 2,  
134 - top : ($(window).height() - $(".loginCenter") .outerHeight()) / 2  
135 - });  
136 - } */  
137 - // 设置两个输入框的高度和左边图片高度一致,宽度为父DIV loginInputDiv减 去三个按钮的宽带度/2*0。8  
138 - /* $(".loginInput").css({  
139 - height : $("#img_user").height(),  
140 - width : ($(".loginInputDiv").width()- $("#img_user").width() * 2 -  
141 - $(".buttonLogin").width()) / 2 * 0.8  
142 - }); */  
143 - // 设置中间登陆框DIV左右居中  
144 - /* $(".loginInputDiv").css({  
145 - left : ($(".loginCenter").outerWidth() - $(".loginInputDiv").outerWidth()) / 2,  
146 - }); */  
147 - $(".buttonLogin").bind("click", function() {  
148 - $(".login-form").submit();  
149 - });  
150 }); 277 });
151 - </script> 278 + }
  279 +
  280 + function checkStatus(){
  281 + var t = nameInput.val();
  282 + if(!t){
  283 + hide();
  284 + return;
  285 + }
  286 +
  287 + $.get('/user/login/captchaStatus', {userName: t}, function(rs){
  288 + if(rs >= 3)
  289 + _captcha.show();
  290 + else
  291 + hide();
  292 + });
  293 +
  294 + function hide(){
  295 + if(!$("#captchaWrap").is(":hidden")){
  296 + _captcha.hide();
  297 + //隐藏提示消息
  298 + msgAlert.html('');
  299 + $('#loginPanel').removeClass('show_msg');
  300 + }
  301 + }
  302 + }
  303 +
  304 +
  305 + var _captcha = {
  306 + show: function(){
  307 + if($("#captchaWrap").is(":hidden")){
  308 + $('#captchaWrap').fadeIn(500);
  309 + _captcha.refresh();
  310 + checkBtnStatus();
  311 + }
  312 + },
  313 + refresh: function(){
  314 + if($("#captchaWrap").is(":hidden"))
  315 + return;
  316 + $('#captchaWrap img.captcha-img').attr('src', '/captcha.jpg?t=' + Math.random());
  317 + },
  318 + hide: function(){
  319 + $('#captchaWrap').hide();
  320 + $('input[name=captcha]').val('');
  321 + }
  322 + };
  323 +
  324 + $('#captchaWrap img.captcha-img').on('click', function(){
  325 + $(this).attr('src', '/captcha.jpg?t=' + Math.random());
  326 + });
  327 +
  328 + function fourBase64(t){
  329 + var ed = $.base64.encode;
  330 + return ed(ed(ed(ed(t))));
  331 + }
  332 +
  333 + function error(rs){
  334 + return rs.status == 'ERROR' || rs.status == 500;
  335 + }
  336 +}();
  337 +</script>
152 </body> 338 </body>
153 -  
154 </html> 339 </html>
155 \ No newline at end of file 340 \ No newline at end of file