Java结合SpringBoot拦截器实现简单的登录认证模块

之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章底部。

1. 环境搭建

IntelliJ IDEA + Java8 + Spring Boot + Tomcat

我将之前项目中的登录模块抽离出来,单独放在了一个新建的Spring Boot项目中;

整个项目的主要结构如下:

参考资料:使用IDEA创建Spring Boot项目

2. 代码详解

2.1 前端代码

之前项目里别的小伙伴已经写好了一个简单的登录框样式表(login.css)和一些image图,我这里就顺手拿来用了,希望哪天你见了眼熟别拍我…

login.vm代码:

注意前端传递给后端Controller的password值并不是用户实际输入的密码!

实际传递的是用户名 + 密码(统一小写)组合的字符串的md5信息值;

这样在前后台数据传递及后台数据保存时传递和保存的都不是用户的真实密码值,可以一定程度提升安全性及规避某些风险;

更多资料可参考:Web前端密码加密是否有意义

<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页的内容,这个页面很简单:

<h1 align="center">登录成功!!!</h1>

<br>
<h3><a href="/loginout"><font color="red">退出登录</font></a></h3>

2.2 后端代码

后端代码相较于前端要复杂一些,让我们来一一拆解;

2.2.1 程序入口

ManApplication.java是整个程序的主入口,因为其上打了@SpringBootApplication的注解;

注意:Spring Boot项目在tomcat上部署运行时,ManApplication需要继承SpringBootServletInitializer

ManApplication.java代码:

/**
* @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);
}
}
2.2.2 Controller

IndexViewController.java类里就是简单的URL映射;

/**
* 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:/";
} }
2.2.3 Interceptor

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 { }
}
2.2.4 Configuration

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");
}
}

3. 踩坑与填坑

3.1 多次重定向与Circle view path错误

刚开始程序部署至tomcat里运行时,理所当然的出现了意想不到的情况,详情如下:

启动时localhost:8080显示:

后台一直报错:

通过断点调试,发现启动后不停地进入IndexViewController中的“/”这个URL映射里;

手动指定访问路径为 localhost:8080/welcome 时后台报错:

解决办法:

  1. 在pom文件中导入thymeleaf依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 在application.properties里添加如下配置:
	spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.vm

我猜想可能是我的view文件都以.vm结尾,thymeleaf默认找的是.html结尾的视图,所以一直找不到;

有知道的大神可以在下面留言详细讲解一下 _

4. 大功告成

4.1 运行截图

未登录情况下访问 localhost:8080/welcome 等非登录页面时会自动跳转到登录页面:

4.2 源码下载

戳这里下载我哟

Java结合SpringBoot拦截器实现简单的登录认证模块的更多相关文章

  1. SpringBoot 拦截器--只允许进入登录注册页面,没登录不允许查看其它页面

    SpringBoot注册登录(一):User表的设计点击打开链接 SpringBoot注册登录(二):注册---验证码kaptcha的实现点击打开链接 SpringBoot注册登录(三):注册--验证 ...

  2. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  3. SpringBoot图文教程7—SpringBoot拦截器的使用姿势这都有

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  4. SpringBoot拦截器中Bean无法注入(转)

    问题 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于其他bean在service,controller层注入一点问题也没有,开始根本没意识到Be ...

  5. SpringBoot拦截器中service或者redis注入为空的问题

    原文:https://my.oschina.net/u/1790105/blog/1490098 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于 ...

  6. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  7. Java三大器之拦截器(Interceptor)的实现原理及代码示例

    1,拦截器的概念    java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了 ...

  8. java 中的拦截器和过滤器

    区别: 1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几 ...

  9. Springboot 拦截器配置(登录拦截)

    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口   HandlerInterceptor, 重写里面需要的三个比较常用的方 ...

随机推荐

  1. 【一天一道LeetCode】#50. Pow(x, n)

    一天一道LeetCode系列 (一)题目 Implement pow(x, n). (二)解题 题目很简单,实现x的n次方. /* 需要注意一下几点: 1.n==0时,返回值为1 2.x==1时,返回 ...

  2. Universal-Image-Loader完全解析--从源代码分析Universal-Image-Loader中的线程池

    一般来讲一个网络访问就需要App创建一个线程来执行,但是这也导致了当网络访问比较多的情况下,线程的数目可能积聚增多,虽然Android系统理论上说可以创建无数个线程,但是某一时间段,线程数的急剧增加可 ...

  3. Protobuf-java maven配置

    Protobuf-java maven配置 1. maven pom片断 <!-- protobuf-java for maven plugin http://stackoverflow.com ...

  4. DBUtils学习总结

    这几天闲着无聊,就看了一下DBUtils这个数据库组件.中间有了一些想法,现在记录下来. 文章主要分几部分 1 最简单同时也是最经常使用的一些范例 2 学习源码前的一些知识储备 3 我自己写的mydb ...

  5. 调用bios喇叭发声

    话不多说,上代码: #include <windows.h> #include <iostream> #include <map> using namespace ...

  6. "《算法导论》之‘线性表’":基于指针实现的单链表

    对于单链表的介绍部分参考自博文数组.单链表和双链表介绍 以及 双向链表的C/C++/Java实现. 1. 单链表介绍 单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针.   ...

  7. Android Notification 版本适配方案

    Notification 介绍见:https://developer.android.com/reference/android/app/Notification.html Android api 一 ...

  8. Linux - 动态(Dynamic)与静态(Static)函数库

    首先我们要知道的是,函式库的类型有哪些?依据函式库被使用的类型而分为两大类,分别是静态 (Static) 与动态 (Dynamic) 函式库两类. 静态函式库的特色: 扩展名:(扩展名为 .a)   ...

  9. Android绘图机制(一)——自定义View的基础属性和方法

    Android绘图机制(一)--自定义View的基础属性和方法 自定义View看起来,确实看起来高深莫测,很多Android开发都不是特别在行这一块,这里面的逻辑以及一些绘画都是有一点难的,说一下我目 ...

  10. C# 压缩PDF图片

    文档中包含图片的话,会使得整个文档比较大,占用存储空间且不利于快速.高效的传输文件.针对一些包含大量高质图片的PDF文档,若是对图片进行压缩,可以有效减少文档的占用空间.并且,在文档传输过程中也可以减 ...