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, 我们运行一波:
-
点击登录后:
-
然后看看SPRING_SESSION表:
-
看看SPRING_SESSION_ATTRIBUTES:
可以看到, 根据spring根据schema创建了两张表
SPRING_SESSION
和SPRING_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