Commit 4f8f35ef054588d426e9b21285a31730000449cd
1 parent
07456ef2
重写登录模块
Showing
9 changed files
with
516 additions
and
212 deletions
pom.xml
| ... | ... | @@ -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<Module, Integer> 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, ">"); | |
| 27 | + s = s.replace(/</g, "<"); | |
| 28 | + s = s.replace(/>/g, ">"); | |
| 29 | + s = s.replace(/ /g, " "); | |
| 30 | + s = s.replace(/\'/g, "'"); | |
| 31 | + s = s.replace(/\"/g, """); | |
| 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 | - | |
| 99 | - <button type="submit" class="btn blue buttonLogin" style="border-radius: 5px !important; | |
| 100 | - font-family: 微软雅黑;">登 录</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 | ... | ... |