RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:8:30-17:00
你可能遇到了下面的问题
关闭右侧工具栏

新闻中心

这里有您想知道的互联网营销解决方案
实战用户登录、Session校验、分布式存储Session

实战 用户登录、SESSION校验、分布式存储Session

作者: 田维常 2021-03-08 09:56:24
存储
存储软件
分布式 一般会将web容器所在的服务器和redis所在的服务器放在同一个机房,减少网络开销,走内网进行连接。

创新互联公司是专业的沙湾网站建设公司,沙湾接单;提供网站设计、成都网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行沙湾网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

实现登录功能

然后再创建login.css存放于在static下,css目录中,id 为 content 的 样式;

  
 
 
 
  1. #content { 
  2.         margin-left: 220px; 
  3.         margin-right: 1420px; 
  4.         margin-top: 100px; 
  5.         margin-bottom: auto; 
  6.         background-color: orange; 
  7.     } 

创建login.html登录页面

   
 
 
 
  1.  
  2.  
  3.  
  4.      
  5.     登录 
  6.      
  7.      
  8.  
  9.  
  10.  
  11.      
  12.     [[${errorMsg}]] 
  13.      
  14.         姓名:
     
  15.         密码:
     
  16.         登录 
  17.      
 
  •  
  •  
  • 前面的这一部分是前端的,下面来把后端代码给写完:

    UserRepository中添加方法的定义:

      
     
     
     
    1. //通过用户名和密码查找用户 
    2. List findByUnameAndPassword(String uname, String password); 

    UserService和实现类中添加方法如下:

      
     
     
     
    1. /通过用户名和密码查找用户 
    2. List findByUnameAndPassword(String uname, String password); 
    3. UserService和实现类中添加方法如下: 
    4.  
    5. // UserService  
    6. User login(User user); 
    7.  
    8. @Service 
    9. //把事务注解放在类上了,这样下面就不需要每次都在方法写这个注解了 
    10. @Transactional(rollbackFor = Exception.class) 
    11. public class UserServiceImpl implements UserService { 
    12.     //...... 
    13.     @Override 
    14.     public User login(User user) { 
    15.         List userList = userRepository.findByUnameAndPassword(user.getUname(), user.getPassword()); 
    16.         //防止有多个用户名相同,并且密码也相同的用户 
    17.         if (!CollectionUtils.isEmpty(userList)) { 
    18.             return userList.get(0); 
    19.         } 
    20.         return null; 
    21.     } 

    UserController中添加方法如下:

      
     
     
     
    1. @RequestMapping(value = "/loginPage", method = RequestMethod.GET) 
    2. public String loginPage(Model model) { 
    3.     return "login"; 
    4.  
    5. @RequestMapping(value = "/login", method = RequestMethod.POST) 
    6. public String login(Model model, User user) { 
    7.     User result = userService.login(user); 
    8.     if (result != null) { 
    9.         //登录成功,跳转到用户列表 
    10.         return "redirect:/userList"; 
    11.     } 
    12.     //不成功,提示 
    13.     model.addAttribute("errorMsg", "用户名或密码不正确"); 
    14.     return "login"; 

    启动项目,访问

    http://localhost:8080/loginPage

    进入登录页面。

    输入用户名密码。密码错误:

    输入正确的用户名和密码,那么跳转到用户列表。

    这样,我们一个简单的登录功能就搞定了。

    如果我们需要在修改用户信息的时候,校验是否已经登录,怎么办呢?

    拦截器

    创建自定义的拦截器并实现HandlerInterceptor接口 。

      
     
     
     
    1. import org.springframework.lang.Nullable; 
    2. import org.springframework.web.servlet.HandlerInterceptor; 
    3. import org.springframework.web.servlet.ModelAndView; 
    4.  
    5. import javax.servlet.http.HttpServletRequest; 
    6. import javax.servlet.http.HttpServletResponse; 
    7.  
    8. public class SessionInterceptor implements HandlerInterceptor { 
    9.     @Override 
    10.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
    11.         //session校验 
    12.         Object object = request.getSession().getAttribute("users"); 
    13.         if (null == object) { 
    14.             response.sendRedirect("/loginPage"); 
    15.             return false; 
    16.         } 
    17.         return true; 
    18.     } 

    创建一个java类继承WebMvcConfiguraeAdapter并重写addInterceptor方法(该类用来添加配置拦截器在该类中添加配置拦截器,以及配置过滤)。

      
     
     
     
    1. import org.springframework.context.annotation.Configuration; 
    2. import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 
    3. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 
    4.  
    5. @Configuration 
    6. public class MyInterceptor extends WebMvcConfigurerAdapter { 
    7.  
    8.     @Override 
    9.     public void addInterceptors(InterceptorRegistry registry) { 
    10.         //可以添加多个拦截 
    11.         registry.addInterceptor(new SessionInterceptor()) 
    12.             //也可以添加多个拦截路径,"/**"拦截所有 
    13.                 .addPathPatterns("/update/**"); 
    14.     } 

    再把登录Controller方法调整,把session信息存进去。

      
     
     
     
    1. @RequestMapping(value = "/login", method = RequestMethod.POST) 
    2. public String login(Model model, User user, HttpServletRequest request) { 
    3.     User result = userService.login(user); 
    4.     if (result != null) { 
    5.         //用户信息保存在session 
    6.         request.getSession().setAttribute("users", user.getUname()); 
    7.         return "redirect:/userList"; 
    8.     } 
    9.     model.addAttribute("errorMsg", "用户名或密码不正确"); 
    10.     return "login"; 

    再次访问用户列表:

    http://localhost:8080/userList

    这时候,我们访问修改用户信息这个功能,跳转到了登录页面。

    登录后,再次访问修改用户信息这个功能。

    这样便来到用户信息修改页面。

    到此,我们就实现了一个简单的session来接校验。

    如果,我们服务器重启后,session就没了,因为session是保存在我们服务端的,并且还是在服务器内存里的。

    session分布式有四种方案

    方案一:客户端存储

    直接将信息存储在cookie中,cookie是存储在客户端上的一小段数据,客户端通过http协议和服务器进行cookie交互,通常用来存储一些不敏感信息

    缺点

    • 数据存储在客户端,存在安全隐患。
    • cookie存储大小、类型存在限制。
    • 数据存储在cookie中,如果一次请求cookie过大,会给网络增加更大的开销。

    方案二:session复制

    session复制是小型企业应用使用较多的一种服务器集群session管理机制,在真正的开发使用的并不是很多,通过对web服务器(例如Tomcat)进行搭建集群。

    缺点

    session同步的原理是在同一个局域网里面通过发送广播来异步同步session的,一旦服务器多了,并发上来了,session需要同步的数据量就大了,需要将其他服务器上的session全部同步到本服务器上,会带来一定的网路开销,在用户量特别大的时候,会出现内存不足的情况。

    优点

    服务器之间的session信息都是同步的,任何一台服务器宕机的时候不会影响另外服务器中session的状态,配置相对简单

    Tomcat内部已经支持分布式架构开发管理机制,可以对tomcat修改配置来支持session复制,在集群中的几台服务器之间同步session对象,使每台服务器上都保存了所有用户的session信息,这样任何一台本机宕机都不会导致session数据的丢失,而服务器使用session时,也只需要在本机获取即可。

    如何配置?

    在Tomcat安装目录下的config目录中的server.xml文件中,将注释打开,tomcat必须在同一个网关内,要不然收不到广播,同步不了session,在web.xml中开启session复制:。

    方案三:session绑定:

    Nginx是一款自由的、开源的、高性能的http服务器和反向代理服务器

    Nginx能做什么?

    反向代理、负载均衡、http服务器(动静代理)、正向代理

    如何使用nginx进行session绑定

    我们利用nginx的反向代理和负载均衡,之前是客户端会被分配到其中一台服务器进行处理,具体分配到哪台服务器进行处理还得看服务器的负载均衡算法(轮询、随机、ip-hash、权重等),但是我们可以基于nginx的ip-hash策略,可以对客户端和服务器进行绑定,同一个客户端就只能访问该服务器,无论客户端发送多少次请求都被同一个服务器处理。

    缺点

    容易造成单点故障,如果有一台服务器宕机,那么该台服务器上的session信息将会丢失

    前端不能有负载均衡,如果有,session绑定将会出问题

    优点

    • 配置简单

    方案四:基于redis存储session方案

    优点

    • 这是企业中使用的最多的一种方式
    • spring为我们封装好了spring-session,直接引入依赖即可
    • 数据保存在redis中,无缝接入,不存在任何安全隐患
    • redis自身可做集群,搭建主从,同时方便管理

    缺点

    多了一次网络调用,web容器需要向redis访问。

    一般会将web容器所在的服务器和redis所在的服务器放在同一个机房,减少网络开销,走内网进行连接。

    来源:http://45dwz.com/xeP0J

    实现基于redis分布式存储session方案

    安装Redis,这里就不说了,不会安装可以联系我。

    集成Redis

    添加依赖

      
     
     
     
    1.  
    2.     org.springframework.boot 
    3.     spring-boot-starter-data-redis 
    4.  
    5.  
    6.  
    7.     org.apache.commons 
    8.     commons-pool2 
    9.  
    10.  
    11.     org.springframework.session 
    12.     spring-session-data-redis 
    13.  

    添加Redis配置

      
     
     
     
    1. # Redis数据库索引(默认为0) 
    2. spring.redis.database=0 
    3. # Redis服务器地址 
    4. spring.redis.host=127.0.0.1 
    5. # Redis服务器连接端口 
    6. spring.redis.port=6379 
    7. # Redis服务器连接密码(默认为空) 
    8. spring.redis.password= 
    9. # 连接池最大连接数(使用负值表示没有限制) 
    10. spring.redis.jedis.pool.max-active=20 
    11. # 连接池最大阻塞等待时间(使用负值表示没有限制) 
    12. spring.redis.jedis.pool.max-wait=-1 
    13. # 连接池中的最大空闲连接 
    14. spring.redis.jedis.pool.max-idle=10 
    15. # 连接池中的最小空闲连接 
    16. spring.redis.jedis.pool.min-idle=0 
    17. # 连接超时时间(毫秒) 
    18. spring.redis.timeout=1000 

    将session添加入Redis中

    在启动类上添加@EnableRedisHttpSession注解。

      
     
     
     
    1. @SpringBootApplication 
    2. @EnableRedisHttpSession 
    3. public class Application { 
    4.     public static void main(String[] args) { 
    5.         SpringApplication.run(Application.class, args); 
    6.     } 

    启动项目,然后,再次登录后,便可以在Redis里查到了

    再次重启项目后,发现修改用户信息的时候,并不需要重新登录了。

    到此,基于Redis分布式存储session方案就已经搞定了。

    总结

    本文首先是实战了登录功能,其次接着实现了校验session拦截处理,然后总结出session分布式四种方案,最后实现了基于redis存储session的方案。

    本文转载自微信公众号「Java后端技术全栈」,可以通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。


    当前名称:实战用户登录、Session校验、分布式存储Session
    文章分享:http://www.jxjierui.cn/article/coojseg.html