Commit 4f8f35ef054588d426e9b21285a31730000449cd

Authored by 潘钊
1 parent 07456ef2

重写登录模块

... ... @@ -180,6 +180,11 @@
180 180 <version>1.4.7</version>
181 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 188 </dependencies>
184 189  
185 190 <dependencyManagement>
... ...
src/main/java/com/bsth/common/Constants.java
... ... @@ -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 17 public static final String LOGIN_PAGE = "/login.html";
18 18 public static final String ASSETS_URL = "/assets/**";
19 19 public static final String FAVICON_URL = "/favicon.ico";
20 20 public static final String METRONIC_URL = "/metronic_v4.5.4/**";
21 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 1 package com.bsth.controller.sys;
2 2  
  3 +import java.util.HashMap;
  4 +import java.util.Map;
  5 +
3 6 import javax.servlet.http.HttpServletRequest;
4 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 13 import org.springframework.beans.factory.annotation.Autowired;
7 14 import org.springframework.security.authentication.BadCredentialsException;
8 15 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
9 16 import org.springframework.security.web.authentication.session.SessionAuthenticationException;
10 17 import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RequestMethod;
11 19 import org.springframework.web.bind.annotation.RequestParam;
12 20 import org.springframework.web.bind.annotation.RestController;
13 21  
  22 +import com.bsth.common.Constants;
  23 +import com.bsth.common.ResponseCode;
14 24 import com.bsth.controller.BaseController;
15 25 import com.bsth.entity.sys.SysUser;
16 26 import com.bsth.security.util.SecurityUtils;
... ... @@ -18,75 +28,158 @@ import com.bsth.service.sys.SysUserService;
18 28  
19 29 @RestController
20 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 35 @Autowired
24 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 122 @RequestMapping("/loginFailure")
35   - public String loginFailure(HttpServletRequest request){
  123 + public String loginFailure(HttpServletRequest request) {
36 124 String msg = "";
37 125 HttpSession session = request.getSession();
38   -
  126 +
39 127 Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
40   -
41   - if(obj instanceof BadCredentialsException)
  128 +
  129 + if (obj instanceof BadCredentialsException)
42 130 msg = "登录失败,用户名或密码错误.";
43   - else if(obj instanceof SessionAuthenticationException)
  131 + else if (obj instanceof SessionAuthenticationException)
44 132 msg = "登录失败,当前策略不允许重复登录.";
45 133 session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
46 134 return msg;
47 135 }
48   -
  136 +
49 137 @RequestMapping("/currentUser")
50   - public SysUser currentUser(){
  138 + public SysUser currentUser() {
51 139 return SecurityUtils.getCurrentUser();
52 140 }
53   -
  141 +
54 142 /**
55 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 149 * @return
60 150 */
61 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 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 165 * @return
73 166 */
74 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 169 SysUser sysUser = SecurityUtils.getCurrentUser();
77 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 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 177 msg = "修改成功!";
85   - }else{
86   - msg= "新密码两次输入不一致!";
  178 + } else {
  179 + msg = "新密码两次输入不一致!";
87 180 }
88 181 }
89   - }else{
  182 + } else {
90 183 msg = "原始密码错误!";
91 184 }
92 185 return msg;
... ...
src/main/java/com/bsth/security/WebSecurityConfig.java
... ... @@ -14,13 +14,11 @@ import org.springframework.security.core.session.SessionRegistryImpl;
14 14 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
15 15 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
16 16 import org.springframework.security.web.authentication.logout.LogoutHandler;
17   -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
18 17 import org.springframework.security.web.session.HttpSessionEventPublisher;
19 18  
20 19 import com.bsth.common.Constants;
21 20 import com.bsth.security.filter.LoginInterceptor;
22 21 import com.bsth.security.handler.CustomLogoutHandler;
23   -import com.bsth.security.handler.LoginSuccessHandler;
24 22  
25 23 @Configuration
26 24 @EnableWebSecurity
... ... @@ -39,7 +37,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
39 37 @Override
40 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 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 56 //指定登录页
59 57 .loginPage(Constants.LOGIN_PAGE)
60 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 61 .and().logout()
67 62 .addLogoutHandler(logoutHandler())
68 63 //禁用CXRF
... ... @@ -92,10 +87,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
92 87 return filterSecurityInterceptor;
93 88 }
94 89  
95   - @Bean
  90 +/* @Bean
96 91 public LoginSuccessHandler loginSuccessHandler(){
97 92 return new LoginSuccessHandler();
98   - }
  93 + }*/
99 94  
100 95 @Bean
101 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 1 package com.bsth.security.util;
2 2  
  3 +import javax.servlet.http.HttpServletRequest;
  4 +
3 5 import org.slf4j.Logger;
4 6 import org.slf4j.LoggerFactory;
  7 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  8 +import org.springframework.security.core.context.SecurityContext;
5 9 import org.springframework.security.core.context.SecurityContextHolder;
6 10  
  11 +import com.bsth.entity.sys.SecurityUser;
7 12 import com.bsth.entity.sys.SysUser;
8 13  
9 14 /**
... ... @@ -33,4 +38,12 @@ public class SecurityUtils {
33 38 }
34 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 1 package com.bsth.service.sys.impl;
2 2  
3 3 import java.util.ArrayList;
4   -import java.util.Collections;
5   -import java.util.Comparator;
6 4 import java.util.HashMap;
7 5 import java.util.HashSet;
8 6 import java.util.List;
... ... @@ -82,6 +80,7 @@ public class ModuleServiceImpl extends BaseServiceImpl&lt;Module, Integer&gt; implemen
82 80 searchParentNode(m, map, pSet);
83 81 }
84 82 results.addAll(pSet);
  83 +
85 84 return results;
86 85 }
87 86  
... ...
src/main/resources/static/assets/js/common.js
... ... @@ -5,7 +5,7 @@
5 5 * success 删除成功之后的回调
6 6 */
7 7 function removeConfirm(text, url, success) {
8   - layer.confirm(text, {
  8 + layer.confirm(html_encode(text), {
9 9 btn : [ '确定删除', '取消' ],
10 10 icon : 3,
11 11 skin : 'layui-layer-cfm-delete'
... ... @@ -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 36 function successHandle(json, handle){
24 37 var status = json.status;
... ...
src/main/resources/static/login.html
... ... @@ -3,152 +3,337 @@
3 3 <head>
4 4 <meta charset="utf-8" />
5 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 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 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 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 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 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 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 148 </style>
83 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 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 338 </body>
153   -
154 339 </html>
155 340 \ No newline at end of file
... ...