Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 424|回复: 0

[默认分类] Java结合SpringBoot拦截器实现简单的登录认证模块

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-16 10:42:13 | 显示全部楼层 |阅读模式
    java结合Springboot拦截器实现简单的登录认证模块
    之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章底部。
    1. 环境搭建
    IntelliJ IDEA + Java8 + Spring Boot + Tomcat
    我将之前项目中的登录模块抽离出来,单独放在了一个新建的Spring Boot项目中;
    整个项目的主要结构如下:

    2. 代码详解
    2.1 前端代码
    之前项目里别的小伙伴已经写好了一个简单的登录框样式表(login.css)和一些image图,我这里就顺手拿来用了,希望哪天你见了眼熟别拍我…
    login.vm代码:
    注意前端传递给后端Controller的password值并不是用户实际输入的密码!
    实际传递的是用户名 + 密码(统一小写)组合的字符串的md5信息值;
    这样在前后台数据传递及后台数据保存时传递和保存的都不是用户的真实密码值,可以一定程度提升安全性及规避某些风险;

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


    1. [code]<html>
    2. <head>
    3.     <title>系统登录</title>
    4.     <meta charset="utf-8"/>
    5.     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    6.     <meta name="author" content="Dreamer-1">
    7.     <meta name="renderer" content="webkit" />
    8.     <link href="/css/login/login.css" rel="stylesheet">
    9.     <script type="text/javascript" src="/js/login/jquery/jquery.min.js?v=20170207"></script>
    10.     <script type="text/javascript" src="/js/login/md5/md5.js"></script>
    11. </head>
    12. <body>
    13.     <form name="form1" method="post" action="/login" id="form1" onsubmit="return checkLogin();">
    14.         <div id="main">
    15.         <div class="wrapper">
    16.             <div class="login-hd"></div>
    17.             <div class="login-body">
    18.                 <div class="logo">
    19.                     <span class="icon-logo"></span>
    20.                 </div>
    21.                 <div class="box">
    22.                     <div class="login-item">
    23.                         <span class="icon-user"></span>
    24.                         <input name="username" type="text" id="username" class="login-input" tabindex="1" maxlength="50" placeholder="请输入用户名" />
    25.                     </div>
    26.                     <div class="login-item mt35">
    27.                         <span class="icon-pwd"></span>
    28.                         <input type="password" id="password" class="login-input" tabindex="2" maxlength="32" placeholder="请输入密码"/>
    29.                         <input type="hidden" id="hidePwd" name="password">
    30.                     </div>
    31.                     <div class="login-forget" style="visibility:hidden">
    32.                         <a href="#">忘记密码</a>
    33.                     </div>
    34.                     <input type="submit" name="Logon" value="登录" id="Logon" tabindex="3" class="login-btn" />
    35.                     <div class="login-bottom">
    36.                         <div class="msg" style="display:none;" >
    37.                             <span class="icon-err"></span>
    38.                             <span id="message"></span>
    39.                         </div>
    40.                     </div>
    41.                 </div>
    42.             </div>
    43.         </div>
    44.         </div>
    45.     </form>
    46.     <script type="text/javascript">
    47.         // onsubmit值为true时,提交表单,否则显示错误信息
    48.         // 生成用户名+密码组合的md5值,并设置传给后端的密码为该md5值
    49.         function checkLogin() {
    50.         var name = $("#username").val().toLowerCase();
    51.         var pwd = $("#password").val().toLowerCase();
    52.         if(name.trim()=="" || pwd.trim()=="") {
    53.             $("#message").text("请输入用户名和密码");
    54.             $(".msg").show();
    55.             return false;
    56.         }else {
    57.             $(".msg").hide();
    58.         }
    59.         var md5info = name + pwd;
    60.         $("#hidePwd").val(md5(md5info));
    61.         //$("#password").val();
    62.         return true;
    63.     }
    64.     </script>
    65. </body>
    66. </html>
    复制代码
    [/code]

    welcome.vm代码
    登录成功后显示welcome.vm页的内容,这个页面很简单:

    1. [code]<h1 align="center">登录成功!!!</h1>
    2. <br>
    3. <h3><a href="/loginout"><font color="red">退出登录</font></a></h3>
    复制代码
    [/code]

    2.2 后端代码
    后端代码相较于前端要复杂一些,让我们来一一拆解;
    2.2.1 程序入口
    ManApplication.java是整个程序的主入口,因为其上打了@SpringBootApplication的注解
    注意:Spring Boot项目在tomcat上部署运行时,ManApplication需要继承
    1. SpringBootServletInitializer
    复制代码

    ManApplication.java代码:

    1. [code]/**
    2. * @SpringBootApplication 注解标明该类是本程序的入口
    3. */
    4. @SpringBootApplication
    5. public class ManApplication extends SpringBootServletInitializer {
    6.     @Override
    7.     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    8.         return application.sources(ManApplication.class);
    9.     }
    10.     public static void main(String[] args) {
    11.         SpringApplication.run(ManApplication.class, args);
    12.     }
    13. }
    复制代码
    [/code]

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

    1. [code]/**
    2. * Created with logindemo.
    3. * Author: dreamer-1
    4. * Email: zhong--lei@outllok.com
    5. * Date: 2018/5/13
    6. * Time: 下午2:58
    7. * Description:
    8. */
    9. @Controller
    10. public class IndexViewController {
    11.     /**
    12. * 登录
    13. * @return
    14. */
    15.     @GetMapping("/")
    16.     public String index() {
    17.         return "login";
    18.     }
    19.     /**
    20. * 欢迎页
    21. * @return
    22. */
    23.     @GetMapping("/welcome")
    24.     public String welcome() {
    25.         return "welcome";
    26.     }
    27. }
    复制代码
    [/code]

    LoginViewController.java类接收前端传过来的username和password,进行简单的校验和重定向;
    此处为了简单就只设置了一个正确的账号和密码用于校验,你后续使用时可以结合自己的实际需求来扩充整个校验逻辑(比如通过专门的表来存储用户登录信息等);
    用户名和密码校验通过后会在当前会话的session中放入一个登录标识,以表示当前用户已经登录;在退出登录或会话超时时销毁该标识;

    1. [code]/**
    2. * Created with logindemo.
    3. * Author: dreamer-1
    4. * Email: zhong--lei@outllok.com
    5. * Date: 2018/5/13
    6. * Time: 下午2:49
    7. * Description:
    8. */
    9. @Controller
    10. public class LoginViewController {
    11.     // 预先设置好的正确的用户名和密码,用于登录验证
    12.     private String rightUserName = "admin";
    13.     private String rightPassword = "admin";
    14.     /**
    15. * 登录校验
    16. *
    17. * @param request
    18. * @return
    19. */
    20.     @RequestMapping("/login")
    21.     public String login(HttpServletRequest request) {
    22.         String username = request.getParameter("username");
    23.         String password = request.getParameter("password");
    24.         if (null == username || null == password) {
    25.             return "redirect:/";
    26.         }
    27.         // 前端传回的密码实际为用户输入的:用户名(小写)+ 密码(小写)组合的字符串生成的md5值
    28.         // 此处先通过后台保存的正确的用户名和密码计算出正确的md5值,然后和前端传回来的作比较
    29.         String md5info = rightUserName.toLowerCase() + rightPassword.toLowerCase();
    30.         String realPassword = DigestUtils.md5DigestAsHex(md5info.getBytes());
    31.         if (!password.equals(realPassword)) {
    32.             return "redirect:/";
    33.         }
    34.         // 校验通过时,在session里放入一个标识
    35.         // 后续通过session里是否存在该标识来判断用户是否登录
    36.         request.getSession().setAttribute("loginName", "admin");
    37.         return "redirect:/welcome";
    38.     }
    39.     /**
    40. * 注销登录
    41. *
    42. * @param request
    43. * @return
    44. */
    45.     @RequestMapping("/loginout")
    46.     public String loginOut(HttpServletRequest request) {
    47.         request.getSession().invalidate();
    48.         return "redirect:/";
    49.     }
    50. }
    复制代码
    [/code]

    2.2.3 Interceptor
    LoginInterceptor.java是整个登录认证模块中的核心类之一,它实现了
    1. HandlerInterceptor
    复制代码
    类,由它来拦截并过滤到来的每一个请求;它的三个方法能分别作用于每个请求的不同生命周期,你可以根据自己的需要来加入相应的处理逻辑;

    1. [code]/**
    2. * Created with logindemo.
    3. * Author: dreamer-1
    4. * Email: zhong--lei@outllok.com
    5. * Date: 2018/5/13
    6. * Time: 下午2:58
    7. * Description:
    8. */
    9. public class LoginInterceptor implements HandlerInterceptor {
    10.     /**
    11. * 在请求被处理之前调用
    12. * @param request
    13. * @param response
    14. * @param handler
    15. * @return
    16. * @throws Exception
    17. */
    18.     @Override
    19.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    20.         // 检查每个到来的请求对应的session域中是否有登录标识
    21.         Object loginName = request.getSession().getAttribute("loginName");
    22.         if (null == loginName || !(loginName instanceof String)) {
    23.             // 未登录,重定向到登录页
    24.             response.sendRedirect("/");
    25.             return false;
    26.         }
    27.         String userName = (String) loginName;
    28.         System.out.println("当前用户已登录,登录的用户名为: " + userName);
    29.         return true;
    30.     }
    31.     /**
    32. * 在请求被处理后,视图渲染之前调用
    33. * @param request
    34. * @param response
    35. * @param handler
    36. * @param modelAndView
    37. * @throws Exception
    38. */
    39.     @Override
    40.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    41.     }
    42.     /**
    43. * 在整个请求结束后调用
    44. * @param request
    45. * @param response
    46. * @param handler
    47. * @param ex
    48. * @throws Exception
    49. */
    50.     @Override
    51.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    52.     }
    53. }
    复制代码
    [/code]

    2.2.4 Configuration
    LoginConfiguration.java是另一个核心类之一,它实现了
    1. WebMvcConfigurer
    复制代码
    类,负责注册并生效我们自己定义的拦截器配置;
    在这里要注意定义好拦截路径和排除拦截的路径;

    1. WebMvcConfigurerAdapter
    复制代码
    其实还可以做很多其他的事,包括添加自定义的视图控制器等等,详见这里


    1. [code]/**
    2. * Created with logindemo.
    3. * Author: dreamer-1
    4. * Email: zhong--lei@outllok.com
    5. * Date: 2018/5/13
    6. * Time: 下午2:58
    7. * Description:
    8. */
    9. @Configuration
    10. public class LoginConfiguration implements WebMvcConfigurer {
    11.     @Override
    12.     public void addInterceptors(InterceptorRegistry registry) {
    13.         // 注册拦截器
    14.         LoginInterceptor loginInterceptor = new LoginInterceptor();
    15.         InterceptorRegistration loginRegistry = registry.addInterceptor(loginInterceptor);
    16.         // 拦截路径
    17.         loginRegistry.addPathPatterns("/**");
    18.         // 排除路径
    19.         loginRegistry.excludePathPatterns("/");
    20.         loginRegistry.excludePathPatterns("/login");
    21.         loginRegistry.excludePathPatterns("/loginout");
    22.         // 排除资源请求
    23.         loginRegistry.excludePathPatterns("/css/login/*.css");
    24.         loginRegistry.excludePathPatterns("/js/login/**/*.js");
    25.         loginRegistry.excludePathPatterns("/image/login/*.png");
    26.     }
    27. }
    复制代码
    [/code]

    3. 踩坑与填坑
    3.1 多次重定向与Circle view path错误
    刚开始程序部署至tomcat里运行时,理所当然的出现了意想不到的情况,详情如下:
    启动时
    1. localhost:8080
    复制代码
    显示:

    后台一直报错:

    通过断点调试,发现启动后不停地进入IndexViewController中的“/”这个URL映射里;
    手动指定访问路径为
    1. localhost:8080/welcome
    复制代码
    时后台报错:

    解决办法:

    在pom文件中导入thymeleaf依赖:


    1. [code]<dependency>
    2.             <groupId>org.springframework.boot</groupId>
    3.             <artifactId>spring-boot-starter-thymeleaf</artifactId>
    4. </dependency>
    复制代码
    [/code]


    在application.properties里添加如下配置:


    1. [code]    spring.thymeleaf.prefix=classpath:/templates/
    2.     spring.thymeleaf.suffix=.vm
    复制代码
    [/code]

    我猜想可能是我的view文件都以.vm结尾,thymeleaf默认找的是.HTML结尾的视图,所以一直找不到;
    有知道的大神可以在下面留言详细讲解一下 ^_^
    4. 大功告成
    4.1 运行截图
    未登录情况下访问
    1. localhost:8080/welcome
    复制代码
    等非登录页面时会自动跳转到登录页面:

    4.2 源码下载
    戳这里下载我哟
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-30 03:41 , Processed in 0.442956 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表