Spring Security Remember Me Beispiel

In diesem Tutorial zeigen wir Ihnen, wie Sie die Anmeldefunktion "Angemeldet bleiben" in Spring Security implementieren. Das bedeutet, dass sich das System an den Benutzer erinnert und auch nach Ablauf der Benutzersitzung eine automatische Anmeldung durchführt.
Verwendete Technologien und Werkzeuge:
-
Feder 3.2.8.FREIGABE
-
Federsicherheit 3.2.3.FREIGABE
-
Spring JDBC 3.2.3.RELEASE
-
Eclipse 4.2
-
JDK 1.6
-
Maven 3
-
MySQL Server 5.6
-
Tomcat 6 und 7 (Servlet 3.x)
-
Testen Sie mit Google Chrome
Einige kurze Notizen:
-
In Spring Security gibt es zwei Ansätze, um "Remember Me" zu implementieren - Simple Hash-Based Token und Persistent Token Approach.
-
Um zu verstehen, wie das "Erinnere dich an mich" funktioniert, lesen Sie bitte diese Artikel -Spring remember me reference,Persistent Login Cookie Best Practice,Improved Persistent Login Cookie Best Practice.
-
In diesem Beispiel wird der "Persistent Token Approach" verwendet. Siehe
PersistentTokenBasedRememberMeServicesvon Spring. -
In diesem Beispiel werden MySQL und die Datenbankauthentifizierung (über Spring JDBC) verwendet.
-
Die Tabelle "persistent_logins" wird erstellt, um das Anmeldetoken und die Serie zu speichern.
Projekt-Workflows:
-
Wenn die Benutzeranmeldung mit einem Häkchen bei "Erinnere dich an mich" aktiviert ist, speichert das System ein "Erinnere dich an mich" -Cookie im angeforderten Browser.
-
Wenn der Browser des Benutzers ein gültiges Cookie zum Erinnern an mich bereitstellt, führt das System eine automatische Anmeldung durch.
-
Wenn sich der Benutzer über "Erinnere dich an mich" -Cookies anmeldet, muss er zum Aktualisieren der Benutzerdetails den Benutzernamen und das Kennwort erneut eingeben (bewährte Methode, um die Aktualisierung der Benutzerinformationen durch gestohlene Cookies zu verhindern).
P.S This is a very high level of how “remember me” should work, for detail, please refer to the above links in “quick notes”.
1. Projekt Demo
2. Projektverzeichnis
Überprüfen Sie die Projektverzeichnisstruktur.

3. MySQL-Skripte
SQL-Skripte zum Erstellen vonusers,user_roles undpersistent_logins.
CREATE TABLE users (
username VARCHAR(45) NOT NULL ,
password VARCHAR(45) NOT NULL ,
enabled TINYINT NOT NULL DEFAULT 1 ,
PRIMARY KEY (username));
CREATE TABLE user_roles (
user_role_id int(11) NOT NULL AUTO_INCREMENT,
username varchar(45) NOT NULL,
role varchar(45) NOT NULL,
PRIMARY KEY (user_role_id),
UNIQUE KEY uni_username_role (role,username),
KEY fk_username_idx (username),
CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username));
INSERT INTO users(username,password,enabled)
VALUES ('example','123456', true);
INSERT INTO user_roles (username, role)
VALUES ('example', 'ROLE_USER');
INSERT INTO user_roles (username, role)
VALUES ('example', 'ROLE_ADMIN');
CREATE TABLE persistent_logins (
username varchar(64) not null,
series varchar(64) not null,
token varchar(64) not null,
last_used timestamp not null,
PRIMARY KEY (series)
);
4. Angemeldet bleiben (XML-Beispiel)
Um "Remember Me" in der XML-Konfiguration zu aktivieren, fügen Sie dasremember-me-Tag wie folgt in diehttp ein:
spring-security.xml
spring-database.xml
-
token-validity-seconds - Das Ablaufdatum des Cookies "Remember-Me" in Sekunden. Zum Beispiel 1209600 = 2 Wochen (14 Tage), 86400 = 1 Tag, 18000 = 5 Stunden.
-
remember-me-parameter - Der Name des Kontrollkästchens. Der Standardwert ist "_spring_security_remember_me".
-
data-source-ref - Wenn dies angegeben ist, wird "Persistent Token Approach" verwendet. Der Standardwert ist "Simple Hash-Based Token Approach".
5. Angemeldet bleiben (Beispiel für Anmerkungen)
Das Äquivalent von Anmerkungen:
SecurityConfig.java
package com.example.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
//...
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin()
.successHandler(savedRequestAwareAuthenticationSuccessHandler())
.loginPage("/login")
.failureUrl("/login?error")
.loginProcessingUrl("/auth/login_check")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/login?logout")
.and()
.csrf()
.and()
.rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(1209600);
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
@Bean
public SavedRequestAwareAuthenticationSuccessHandler
savedRequestAwareAuthenticationSuccessHandler() {
SavedRequestAwareAuthenticationSuccessHandler auth
= new SavedRequestAwareAuthenticationSuccessHandler();
auth.setTargetUrlParameter("targetUrl");
return auth;
}
}
P.S In annotation configuration, the default http name for “remember me” check box is “remember-me”.
6.HTML / JSP Pages
6.1 In JSP, you can use Spring security tag sec:authorize access="isRememberMe()" to determine if this user is login by “remember me” cookies.
admin.jsp
<%@taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
Title : ${title}
Message : ${message}
Welcome : ${pageContext.request.userPrincipal.name} | Logout
# This user is login by "Remember Me Cookies".
# This user is login by username / password.
6.2 A simple login form with “remember me” check box.
login.jsp
6.3 Update page. Nur Benutzer, die sich mit einem Passwort anmelden, dürfen auf diese Seite zugreifen.
update.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
Title : Spring Security Remember Me Example - Update Form
Message : This page is for ROLE_ADMIN and fully authenticated only
(Remember me cookie is not allowed!)
Update Account Information...
7. Regler
Spring-Controller-Klasse, lesen Sie den Kommentar für selbsterklärende.
MainController.java
package com.example.web.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MainController {
@RequestMapping(value = { "/", "/welcome**" }, method = RequestMethod.GET)
public ModelAndView defaultPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security Remember Me");
model.addObject("message", "This is default page!");
model.setViewName("hello");
return model;
}
@RequestMapping(value = "/admin**", method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView model = new ModelAndView();
model.addObject("title", "Spring Security Remember Me");
model.addObject("message", "This page is for ROLE_ADMIN only!");
model.setViewName("admin");
return model;
}
/**
* This update page is for user login with password only.
* If user is login via remember me cookie, send login to ask for password again.
* To avoid stolen remember me cookie to update info
*/
@RequestMapping(value = "/admin/update**", method = RequestMethod.GET)
public ModelAndView updatePage(HttpServletRequest request) {
ModelAndView model = new ModelAndView();
if (isRememberMeAuthenticated()) {
//send login for update
setRememberMeTargetUrlToSession(request);
model.addObject("loginUpdate", true);
model.setViewName("/login");
} else {
model.setViewName("update");
}
return model;
}
/**
* both "normal login" and "login for update" shared this form.
*
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout,
HttpServletRequest request) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
//login form for update page
//if login error, get the targetUrl from session again.
String targetUrl = getRememberMeTargetUrlFromSession(request);
System.out.println(targetUrl);
if(StringUtils.hasText(targetUrl)){
model.addObject("targetUrl", targetUrl);
model.addObject("loginUpdate", true);
}
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
/**
* Check if user is login by remember me cookie, refer
* org.springframework.security.authentication.AuthenticationTrustResolverImpl
*/
private boolean isRememberMeAuthenticated() {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return false;
}
return RememberMeAuthenticationToken.class.isAssignableFrom(authentication.getClass());
}
/**
* save targetURL in session
*/
private void setRememberMeTargetUrlToSession(HttpServletRequest request){
HttpSession session = request.getSession(false);
if(session!=null){
session.setAttribute("targetUrl", "/admin/update");
}
}
/**
* get targetURL from session
*/
private String getRememberMeTargetUrlFromSession(HttpServletRequest request){
String targetUrl = "";
HttpSession session = request.getSession(false);
if(session!=null){
targetUrl = session.getAttribute("targetUrl")==null?""
:session.getAttribute("targetUrl").toString();
}
return targetUrl;
}
}
8. Demo
8.1 Access protected page – http://localhost:8080/spring-security-remember-me/admin, the system will redirect user to a login form. Versuchen Sie sich mit aktiviertem "Remember Me" anzumelden.


8.2 In Google Chrome, Settings → Show advanced settings → Privacy, Content Setting… → “All cookies and site data” – there are two cookies for localhost, one for current session and one for “remember me” login cookies.

8.3 Review table “persistent_logins”, username, series and token is stored.

8.4 Restart the web application, go Chrome “All cookies and site data”, and remove the browser’s session “JSESSIONID”. Versuchen Sie erneut, auf die Anmeldeseite zuzugreifen. Das System wird sich nun an Sie erinnern und sich automatisch über die Login-Cookies in Ihrem Browser anmelden.

8.5 Try to access the “update” page – http://localhost:8080/spring-security-remember-me/admin/update, if user is login by remember me cookies, the system will redirect user to login form again. Dies ist eine gute Vorgehensweise, um zu vermeiden, dass gestohlene Cookies Benutzerdetails aktualisieren.

8.6 Done.

9. Misc
Einige wichtige Spring Security-Kurse zum Lernen:
-
org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer.java
-
org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.java
-
org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.java
-
org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.java
-
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter
Quellcode herunterladen
Laden Sie es herunter -spring-security-remember-me.zip (18 KB)
Laden Sie es herunter -spring-security-remember-me-annotation.zip (25 KB)