SpringSecurity-8-自動ログインおよびログアウト機能の実装
自動ログインの実装
特定のウェブサイトにログインするときは、アカウントとパスワードを使用してログインしますが、毎回ブラウザを閉じたくないので、毎回アカウントとパスワードを再入力したくありません。ユーザーのログイン体験に合わせ、ユーザーの利便性を高めます。自動ログイン機能を使用してログイン情報をブラウザのCookieに保存し、ユーザーが次回アクセスしたときに自動的に新しいログインステータスを確認して作成できるようにします。しかし、これはまた、ユーザーに情報漏えいの危険をもたらします。
自動ログインプロセス
-
ユーザーが正常にログインしたことを記憶することを選択すると、サーバー上でCookieが生成され、ブラウザーに返されます。Cookieのデフォルト名はremember-meで、値はトークンです。
-
ユーザーが再訪すると、remember-me cookieに対応するトークン値が最初にチェックされます。トークン値が存在する場合、トークン値のユーザー名、シリアル番号、およびトークン値がによって生成されたものと同じであるかどうかがチェックされます。それらが同じである場合、それらは合格します。また、システムは新しいトークンを再生成します。シリアル化シリーズは変更されません。古いCookieを削除し、新しいCookieを再生成して、クライアントに保存します。
-
Cookieが存在しない場合、またはユーザー名、シリアル化されたシリーズ、トークンがサーバー上のものと異なる場合は、ログインページに戻ります。
Cookieが盗まれる可能性があるため、アプリケーションのセキュリティが比較的高い場合は、remember-me関数を使用しないでください。
ハッシュ復号化スキーム
SpringSecurityが自動ログイン機能を実装するのは非常に簡単です
login.htmlを変更します
login.htmlにrememberme関数を追加する必要があります。htmlの実装は次のとおりです。
<!--suppress ALL-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>springboot葵花宝典登录页面</title>
<!-- Tell the browser to be responsive to screen width -->
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>springboot葵花宝典登录页面</h1>
<form th:action="@{/login/form}" action="index.html" method="post">
<span>用户名称</span><input type="text" name="username" /> <br>
<span>用户密码</span><input type="password" name="password" /> <br>
<div >
<input name="code" type="text" class="form-control" placeholder="验证码">
<img onclick="this.src='/code/image?'+Math.random()" src="/code/image" alt="验证码" />
</div> <br>
<span>记住我</span><input type="checkbox" name="remember-me" > <br>
<div th:if="${param.error}">
<span th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}" style="color:#ff0000">用户名或 密码错误</span>
</div>
<input type="submit" value="登陆">
</form>
</body>
</html>
复制代码
結果を変更すると、ログインページが次のように表示されます。
LearnSrpingSecurityを変更する
configure(HttpSecurity http)メソッドで構成を覚えておいてください。コードは次のように実装されています。
テスト
重新启动程序,使用浏览器访问http://localhost:8888/login/page,然后输入账号密码进行登录,结果如下
从图上我们可以看出来,勾选“Remember me”可选框(简写为Remember-me),按照正常的流程登录,并在 开发者工具中查看浏览器cookie,可以看到除JSESSIONID外多了一个值。
cookie个性化配置
在实际的开发过程中,我们还可以根据需求做一些个性化的设置,如下:
.rememberMe()
.rememberMeParameter("remember-me-new")
.rememberMeCookieName("remember-me-cookie")
复制代码
-
通过rememberMeParameter设置from表单“自动登录”勾选框的参数名称。如果这里改了,from表单中checkbox的name属性要对应的更改。如果不设置默认是remember-me。
-
rememberMeCookieName设置了保存在浏览器端的cookie的名称,如果不设置默认也是remember-me。如下图中查看浏览器的cookie。
持久化令牌方案
持久化令牌方案是交互方式上和散列加密方案一致,都是用户勾选remember-me
后,将生成的令牌发送到用户的客户端,用户在下次进行访问的时候会读取该令牌,不同的是会将数据保存到数据库中。
添加数据库依赖
我们在项目中的pom.xml中添加数据库依赖
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
复制代码
application.yml中添加数据库配置
spring:
thymeleaf:
cache: false
datasource:
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
复制代码
使用 JdbcTokenRepository 实现类
在LearnSrpingSecurity配置类中注入DataSource
和JdbcTokenRepositoryImpl
,实现如下
@Autowired
private DataSource dataSource;
@Bean
public JdbcTokenRepositoryImpl jdbcTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
复制代码
安全配置 LearnSrpingSecurity#confifigure(HttpSecurity http)
在LearnSrpingSecurity的confifigure(HttpSecurity http)方法中添加如下配置
.and()
.rememberMe()
.userDetailsService(customUserDetailsService)
.tokenRepository(jdbcTokenRepository())
.tokenValiditySeconds(60)
.rememberMeParameter("remember-me-test")
.rememberMeCookieName("remember-me-cookie")
复制代码
测试效果
-
重启项目后,数据库会自动创建表 persistent_logins
-
访问首页跳转到登录页面,登录成功后,查看浏览器 cookies,保存 token 值,在数据库中也有数据。
-
再重启,Session会清除。再次访问首页,不会跳转到登录页,因为上次已经记录了。这时浏览器Cookie中保存的token从数据库查找用户名,然后进行自动登录。
报错
Caused by: java.sql.SQLSyntaxErrorException: Table 'persistent_logins' already exists
解决方法:
将JdbcTokenRepositoryImpl方法中jdbcTokenRepository.setCreateTableOnStartup(true)注释掉
@Bean
public JdbcTokenRepositoryImpl jdbcTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
复制代码
退出系统
其实使用Spring Security进行logout非常简单,只需要在spring Security配置类配置项上加上这样一行代码:http.logout()。
修改index.html
我们在index.html中添加退出系统功能,实现如下
<!--suppress ALL-->
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>springboot葵花宝典管理系统</title>
</head>
<body>
<a th:href="@{/logout}" href="login.html" > <span>退出系统</span> </a>
<h1>springboot葵花宝典管理系统</h1>
<br>
<a href="/syslog">日志管理</a>
<br>
<a href="/sysuser">用户管理</a>
</body>
复制代码
测试
重新启动项目后,登录成功后展示页面如下,退出登录后,我们发现remember-me-cookie已经删除。虽然我们简简单单的实现了logout功能,是不是还不足够放心?我们下面就来看一下Spring Security默认在logout过程中帮我们做了哪些动作。
-
当前session失效,即:logout的核心需求,session失效就是访问权限的回收。
-
删除当前用户的 remember-me“记住我”功能信息
-
clear清除当前的 SecurityContext
-
重定向到登录页面,loginPage配置项指定的页面
个性化配置
虽然Spring Security默认使用了/logout作为退出处理请求路径,登录页面作为退出之后的跳转页面。这符合绝大多数的应用的开发逻辑,但有的时候我们需要一些个性化设置,如下
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login/page")
.deleteCookies("JSESSIONID")
复制代码
-
指定logoutUrl配置修改默认的logout路径,同时html退出按钮的请求url也要修改
-
指定logoutSuccessUrl配置,指定退出之后的跳转页面
-
使用deleteCookies删除指定的cookie,参数为cookie的名称