以前在作项目时须要实现一个简单的登陆认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下个人整个实现过程,源码见文章底部。javascript
IntelliJ IDEA + Java8 + Spring Boot + Tomcat
我将以前项目中的登陆模块抽离出来,单独放在了一个新建的Spring Boot项目中;
整个项目的主要结构以下:
css
参考资料:使用IDEA建立Spring Boot项目html
以前项目里别的小伙伴已经写好了一个简单的登陆框样式表(login.css)和一些image图,我这里就顺手拿来用了,但愿哪天你见了眼熟别拍我…
login.vm代码:
注意前端传递给后端Controller的password值并不是用户实际输入的密码!
实际传递的是用户名 + 密码(统一小写)组合的字符串的md5信息值;
这样在先后台数据传递及后台数据保存时传递和保存的都不是用户的真实密码值,能够必定程度提高安全性及规避某些风险;前端
更多资料可参考:Web前端密码加密是否有意义java
<html> <head> <title>系统登陆</title> <meta charset="utf-8"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="author" content="Dreamer-1"> <meta name="renderer" content="webkit" /> <link href="/css/login/login.css" rel="stylesheet"> <script type="text/javascript" src="/js/login/jquery/jquery.min.js?v=20170207"></script> <script type="text/javascript" src="/js/login/md5/md5.js"></script> </head> <body> <form name="form1" method="post" action="/login" id="form1" onsubmit="return checkLogin();"> <div id="main"> <div class="wrapper"> <div class="login-hd"></div> <div class="login-body"> <div class="logo"> <span class="icon-logo"></span> </div> <div class="box"> <div class="login-item"> <span class="icon-user"></span> <input name="username" type="text" id="username" class="login-input" tabindex="1" maxlength="50" placeholder="请输入用户名" /> </div> <div class="login-item mt35"> <span class="icon-pwd"></span> <input type="password" id="password" class="login-input" tabindex="2" maxlength="32" placeholder="请输入密码"/> <input type="hidden" id="hidePwd" name="password"> </div> <div class="login-forget" style="visibility:hidden"> <a href="#">忘记密码</a> </div> <input type="submit" name="Logon" value="登陆" id="Logon" tabindex="3" class="login-btn" /> <div class="login-bottom"> <div class="msg" style="display:none;" > <span class="icon-err"></span> <span id="message"></span> </div> </div> </div> </div> </div> </div> </form> <script type="text/javascript"> // onsubmit值为true时,提交表单,不然显示错误信息 // 生成用户名+密码组合的md5值,并设置传给后端的密码为该md5值 function checkLogin() { var name = $("#username").val().toLowerCase(); var pwd = $("#password").val().toLowerCase(); if(name.trim()=="" || pwd.trim()=="") { $("#message").text("请输入用户名和密码"); $('.msg').show(); return false; }else { $('.msg').hide(); } var md5info = name + pwd; $('#hidePwd').val(md5(md5info)); //$("#password").val(); return true; } </script> </body> </html>
welcome.vm代码
登陆成功后显示welcome.vm页的内容,这个页面很简单:jquery
<h1 align="center">登陆成功!!!</h1> <br> <h3><a href="/loginout"><font color="red">退出登陆</font></a></h3>
后端代码相较于前端要复杂一些,让咱们来一一拆解;web
ManApplication.java是整个程序的主入口,由于其上打了@SpringBootApplication的注解;
注意:Spring Boot项目在tomcat上部署运行时,ManApplication须要继承SpringBootServletInitializer
类
ManApplication.java代码:spring
/** * @SpringBootApplication 注解标明该类是本程序的入口 */ @SpringBootApplication public class ManApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(ManApplication.class); } public static void main(String[] args) { SpringApplication.run(ManApplication.class, args); } }
IndexViewController.java类里就是简单的URL映射;chrome
/** * Created with logindemo. * Author: dreamer-1 * Email: zhong--lei@outllok.com * Date: 2018/5/13 * Time: 下午2:58 * Description: */ @Controller public class IndexViewController { /** * 登陆 * @return */ @GetMapping("/") public String index() { return "login"; } /** * 欢迎页 * @return */ @GetMapping("/welcome") public String welcome() { return "welcome"; } }
LoginViewController.java类接收前端传过来的username和password,进行简单的校验和重定向;
此处为了简单就只设置了一个正确的帐号和密码用于校验,你后续使用时能够结合本身的实际需求来扩充整个校验逻辑(好比经过专门的表来存储用户登陆信息等);
用户名和密码校验经过后会在当前会话的session中放入一个登陆标识,以表示当前用户已经登陆;在退出登陆或会话超时时销毁该标识;后端
/** * Created with logindemo. * Author: dreamer-1 * Email: zhong--lei@outllok.com * Date: 2018/5/13 * Time: 下午2:49 * Description: */ @Controller public class LoginViewController { // 预先设置好的正确的用户名和密码,用于登陆验证 private String rightUserName = "admin"; private String rightPassword = "admin"; /** * 登陆校验 * * @param request * @return */ @RequestMapping("/login") public String login(HttpServletRequest request) { String username = request.getParameter("username"); String password = request.getParameter("password"); if (null == username || null == password) { return "redirect:/"; } // 前端传回的密码实际为用户输入的:用户名(小写)+ 密码(小写)组合的字符串生成的md5值 // 此处先经过后台保存的正确的用户名和密码计算出正确的md5值,而后和前端传回来的做比较 String md5info = rightUserName.toLowerCase() + rightPassword.toLowerCase(); String realPassword = DigestUtils.md5DigestAsHex(md5info.getBytes()); if (!password.equals(realPassword)) { return "redirect:/"; } // 校验经过时,在session里放入一个标识 // 后续经过session里是否存在该标识来判断用户是否登陆 request.getSession().setAttribute("loginName", "admin"); return "redirect:/welcome"; } /** * 注销登陆 * * @param request * @return */ @RequestMapping("/loginout") public String loginOut(HttpServletRequest request) { request.getSession().invalidate(); return "redirect:/"; } }
LoginInterceptor.java是整个登陆认证模块中的核心类之一,它实现了HandlerInterceptor
类,由它来拦截并过滤到来的每个请求;它的三个方法能分别做用于每一个请求的不一样生命周期,你能够根据本身的须要来加入相应的处理逻辑;
/** * Created with logindemo. * Author: dreamer-1 * Email: zhong--lei@outllok.com * Date: 2018/5/13 * Time: 下午2:58 * Description: */ public class LoginInterceptor implements HandlerInterceptor { /** * 在请求被处理以前调用 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 检查每一个到来的请求对应的session域中是否有登陆标识 Object loginName = request.getSession().getAttribute("loginName"); if (null == loginName || !(loginName instanceof String)) { // 未登陆,重定向到登陆页 response.sendRedirect("/"); return false; } String userName = (String) loginName; System.out.println("当前用户已登陆,登陆的用户名为: " + userName); return true; } /** * 在请求被处理后,视图渲染以前调用 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } /** * 在整个请求结束后调用 * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
LoginConfiguration.java是另外一个核心类之一,它实现了WebMvcConfigurer
类,负责注册并生效咱们本身定义的拦截器配置;
在这里要注意定义好拦截路径和排除拦截的路径;
WebMvcConfigurerAdapter
其实还能够作不少其余的事,包括添加自定义的视图控制器等等,详见这里
/** * Created with logindemo. * Author: dreamer-1 * Email: zhong--lei@outllok.com * Date: 2018/5/13 * Time: 下午2:58 * Description: */ @Configuration public class LoginConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 注册拦截器 LoginInterceptor loginInterceptor = new LoginInterceptor(); InterceptorRegistration loginRegistry = registry.addInterceptor(loginInterceptor); // 拦截路径 loginRegistry.addPathPatterns("/**"); // 排除路径 loginRegistry.excludePathPatterns("/"); loginRegistry.excludePathPatterns("/login"); loginRegistry.excludePathPatterns("/loginout"); // 排除资源请求 loginRegistry.excludePathPatterns("/css/login/*.css"); loginRegistry.excludePathPatterns("/js/login/**/*.js"); loginRegistry.excludePathPatterns("/image/login/*.png"); } }
刚开始程序部署至tomcat里运行时,理所固然的出现了意想不到的状况,详情以下:
启动时localhost:8080
显示:
后台一直报错:
经过断点调试,发现启动后不停地进入IndexViewController中的“/”这个URL映射里;
手动指定访问路径为 localhost:8080/welcome
时后台报错:
解决办法:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.vm
我猜测多是个人view文件都以.vm结尾,thymeleaf默认找的是.html结尾的视图,因此一直找不到;
有知道的大神能够在下面留言详细讲解一下 ^_^
未登陆状况下访问 localhost:8080/welcome
等非登陆页面时会自动跳转到登陆页面: