Springboot登录会话过期,重定向到登录界面

Springboot实现登录过期,重定向到登录页面

集成spring session

很多时候我们网站都会需要登录和验证.

试想: 如果我登录了网站后, 有事离开了电脑60分钟; 在这段时间内, 如果有人使用我的电脑, 那么我的账号是十分危险的.

因此需要一个浏览器与服务器之间的会话, 在没有一定时间内没有交互的话, 就让这次登陆状态过期, 如果过期后, 在页面上点击, 让它跳转回登陆页面.

这个会话就叫做session.

spring支持很多种类的session. 如 Jdbc session, Redis session, MongoDB session

它们的原理都是将 会话信息: 会话id, 会话创建时间会话失效时间等 存在数据库

下面我会使用Spring Jdbc Session 来作为我的例子

  • 添加jdbc session 依赖

    <dependency>
    			<groupId>org.springframework.session</groupId>
    			<artifactId>spring-session-jdbc</artifactId>
    </dependency>
    
  • 在application.properties里配置session 和 数据源

    # 设置使用jdbc的方式存储session
    spring.session.store-type=jdbc
    # session 过期时间, 为了快速看到过期效果,我设置的60, 通常是设置为30分钟
    server.servlet.session.timeout=60s
    # Database schema 初始化模式
    spring.session.jdbc.initialize-schema=always
    # datasource schema
    spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-mysql.sql
    # 存放session的表名, 此表无须手动创建, spring会自己来维护session的添加和移除
    # spring会通过上面设置的schema-mysql.sql进行自动创建保存会话的表名,
    # 前提是你的数据库要能正确配置, 我在下面配置了我的数据库
    spring.session.jdbc.table-name=SPRING_SESSION
    
    # mysql数据库url
    spring.datasource.url=jdbc:mysql://localhost:3306/common?characterEncoding=utf8
    # 数据库用户名
    spring.datasource.username=root
    # 数据库 密码
    spring.datasource.password=root
    # 连接数据库驱动
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    

    上面的Spring_SESSION表会根据schema-mysql文件自动创建,

    当你使用 session.setAttribute("name", username);时, spring会自动在表中插入一条记录,

    并根据配置文件设置的过期时间来设置会话过期时间, 在相应时间浏览器与服务器无交互后,便

    自动在表中移除这条记录, 即移除了会话.

  • 设置schema-mysql, spring会根据这个sql文件来建表

    文件路径为: src/main/resources/org/springframework/session/jdbc/schema-mysql.sql

    CREATE TABLE SPRING_SESSION (
        PRIMARY_ID CHAR(36) NOT NULL,
        SESSION_ID CHAR(36) NOT NULL,
        CREATION_TIME BIGINT NOT NULL,
        LAST_ACCESS_TIME BIGINT NOT NULL,
        MAX_INACTIVE_INTERVAL INT NOT NULL,
        EXPIRY_TIME BIGINT NOT NULL,
        PRINCIPAL_NAME VARCHAR(100),
        CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
    ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
    
    CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
    CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
    CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
    
    CREATE TABLE SPRING_SESSION_ATTRIBUTES (
        SESSION_PRIMARY_ID CHAR(36) NOT NULL,
        ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
        ATTRIBUTE_BYTES BLOB NOT NULL,
        CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
        CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
    ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
    

    ok, 现在我们已经集成了jdbc session了.

    接下来写filter来过滤请求. 当判断会话为空时, 跳转到index界面

保存会话信息

@RestController
@RequestMapping("/control")
public class LoginController {
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public RedirectView login(String username, String password, HttpSession session, HttpServletResponse response, Model model) {
        session.setAttribute("name", username);
        RedirectView redirectView = new RedirectView("filter/home");
        return redirectView;
    }
}
  • 前端简单写个登录表单

    设置提交action="/control/login", 然后有两个输入框, 它们的name分别为 username, password

    对应/control/login注释的这个方法.

    可以看到我在login方法里, 设置了session.setAttribute("name", username);, 即把输入的username保存在session会话中.

    ok, 我们运行一波:

    Springboot登录会话过期,重定向到登录界面_第1张图片

  • 点击登录后:

    Springboot登录会话过期,重定向到登录界面_第2张图片

  • 然后看看SPRING_SESSION表:

    Springboot登录会话过期,重定向到登录界面_第3张图片

  • 看看SPRING_SESSION_ATTRIBUTES:

    Springboot登录会话过期,重定向到登录界面_第4张图片

    可以看到, 根据spring根据schema创建了两张表SPRING_SESSIONSPRING_SESSION_ATTRIBUTES, 一个存放session会话记录, 另一个存放session里面放的属性值.

    在第一张图里我们可以看到失效时间 60s, 第二张图里可以看到我们通过session.setAttribute("name", username);存放的属性,

    数据库中 ATTRIBUTR_NAME那一列有name这个属性, 并且它的主键与session表id关联.

    60s后, spring会自动删除数据库里的session, session_attribute里面的记录.

实现Filter过滤请求

  • 实现Filter

    /**
     * @Author wuwei
     * @Date 2019/12/15 1:09 下午
     */
    @WebFilter(urlPatterns = {"/control/filter/*"})
    public class SessionFilter implements Filter {
        @Override
        public void destroy() {
            System.out.println("filter destroy");
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("filter init");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest servlet = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            //取出session里面的name属性,如果name为空, 就重定向到index界面
            String name = (String) servlet.getSession().getAttribute("name");
            if (Objects.isNull(name)){
                response.sendRedirect("/control/index");
                return;
            }
            //name属性存在, 即会话没有过期, 那么允许本次请求
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
    
  • 为application加上注解@ServletComponentScan, 以便spring扫描到filter

    @SpringBootApplication
    @ServletComponentScan
    public class SecurityApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(SecurityApplication.class, args);
    	}
    
    }
    

测试

我把会话过期时间设置为5s, 便于立刻看到效果

然后登录后, 过5s再刷新浏览器, 直接跳转到首页登录.

Over

如果觉得需要更多技术干货, 来我的CSDN 和 GitHub哦

CSDN: https://blog.csdn.net/dummyo

Github: https://github.com/uweii

你可能感兴趣的:(springboot,java碎碎片,框架)