SpringBoot - 安全入门与SpringSecurity

简介: SpringBoot - 安全入门与SpringSecurity

市面上有两种常见的安全框架,Shiro和SpringSecurity。功能都很强大,用户数量也都很多。SpringSecurity优势在于能和Spring无缝衔接。

Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型。他可以实现强大的web安全控制。对于安全控制,我们仅需引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。


【1】认证和授权

应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。这两个主要区域是Spring Security 的两个目标。

“认证”(Authentication),是建立一个他声明的主体的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统)。

“授权”(Authorization)指确定一个主体是否允许在你的应用程序执行一个动作的过程。为了抵达需要授权的店,主体的身份已经有认证过程建立。

这个概念是通用的而不只在Spring Security中。


【2】Spring Security

使用注解@EnableWebSecurity开启WebSecurity模式。

该注解源码如下:

/**
 * Add this annotation to an {@code @Configuration} class to have the Spring Security
 * configuration defined in any {@link WebSecurityConfigurer} or more likely by extending
 * the {@link WebSecurityConfigurerAdapter} base class and overriding individual methods:
 *在配置类上添加该注解使其获得Spring Security配置,该配置被定义在任何
 WebSecurityConfigurer中或继承自WebSecurityConfigurerAdapter并重写方法的
 类中,后者如下所示:
 * <pre class="code">
 * &#064;Configuration
 * &#064;EnableWebSecurity
 * public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
 *
 *  &#064;Override
 *  public void configure(WebSecurity web) throws Exception {
 *    web.ignoring()
 *    // Spring Security should completely ignore URLs starting with /resources/
 *        .antMatchers(&quot;/resources/**&quot;);
 *  }
 *
 *  &#064;Override
 *  protected void configure(HttpSecurity http) throws Exception {
 *    http.authorizeRequests().antMatchers(&quot;/public/**&quot;).permitAll().anyRequest()
 *        .hasRole(&quot;USER&quot;).and()
 *        // Possibly more configuration ...
 *        .formLogin() // enable form based log in
 *        // set permitAll for all URLs associated with Form Login
 *        .permitAll();
 *  }
 *
 *  &#064;Override
 *  protected void configure(AuthenticationManagerBuilder auth) {
 *    auth
 *    // enable in memory based authentication with a user named &quot;user&quot; and &quot;admin&quot;
 *    .inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;)
 *        .and().withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
 *  }
 *
 *  // Possibly more overridden methods ...
 * }
 * </pre>
 *
 * @see WebSecurityConfigurer
 * @see WebSecurityConfigurerAdapter
 *
 * @author Rob Winch
 * @since 3.2
 */
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
    SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication//开启全局权限配置
@Configuration// 这里引用了@Configuration该注解
public @interface EnableWebSecurity {
  /**
   * Controls debugging support for Spring Security. Default is false.
   * @return if true, enables debug support with Spring Security
   */
  boolean debug() default false;
}

两个重要的类:

WebSecurityConfigurerAdapter:自定义Security策略

AuthenticationManagerBuilder:自定义认证策略



【3】源码与测试

① 基础环境

默认欢迎页面如下(未登录状态),不同权限可以查看不同武功秘籍:



② 引入SpringSecurity

Starter如下:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

自定义Security配置类初始如下:

@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    // 如下,定制请求的授权规则
        http.authorizeRequests()
            .antMatchers("/css/**", "/").permitAll()
            .antMatchers("/level1/**").hasRole("VIP1")
            .antMatchers("/level2/**").hasRole("VIP2")
            .antMatchers("/level3/**").hasRole("VIP3")
    }
}

此时再访问任意武林秘籍,则会提示访问被拒绝如下图:


③ 开启自动配置的登录功能

**http.formLogin();**方法会自动创建默认登录页。默认/login请求就会来到登录页,如果登录失败则会重定向到/login?error。也可以自定义登录页,查看HttpSecurity.formLogin()源码示例如下:

/**
   * Specifies to support form based authentication.
   * //指定支持基于表单的身份验证。 
   * If
   * {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page
   * will be generated.
   *// 如果登录页没有指定,则会创建一个默认登录页
   * <h2>Example Configurations</h2>
   *
   * The most basic configuration defaults to automatically generating a login page at
   * the URL "/login", redirecting to "/login?error" for authentication failure. The
   * details of the login page can be found on
   * {@link FormLoginConfigurer#loginPage(String)}
   *
   * <pre>
   * &#064;Configuration
   * &#064;EnableWebSecurity
   * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
   *
   *  &#064;Override
   *  protected void configure(HttpSecurity http) throws Exception {
   *    http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin();
   *  }
   *
   *  &#064;Override
   *  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   *    auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;);
   *  }
   * }
   * </pre>
   *
   * The configuration below demonstrates customizing the defaults.
   *
   * <pre>
   * &#064;Configuration
   * &#064;EnableWebSecurity
   * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
   *// 着重观察如下配置示例 !!!
   *  &#064;Override
   *  protected void configure(HttpSecurity http) throws Exception {
   *    http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin()
   *        .usernameParameter(&quot;username&quot;) // default is username
   *        .passwordParameter(&quot;password&quot;) // default is password
   *        .loginPage(&quot;/authentication/login&quot;) // default is /login with an HTTP get
   *        .failureUrl(&quot;/authentication/login?failed&quot;) // default is /login?error
   *        .loginProcessingUrl(&quot;/authentication/login/process&quot;); // default is /login
   *                                    // with an HTTP
   *                                    // post
   *  }
   *
   *  &#064;Override
   *  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   *    auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;);
   *  }
   * }
   * </pre>
   *
   * @see FormLoginConfigurer#loginPage(String)
   *
   * @return
   * @throws Exception
   */
  public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
    return getOrApply(new FormLoginConfigurer<HttpSecurity>());
  }

此时还配置任何用户,没有登录没有权限,访问Level1,会跳向默认的登录页:


④ 为系统添加用户、密码和角色

配置类中添加方法:

  @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("zhangsan").password("123456").roles("VIP1","VIP2")
                .and()
                .withUser("lisi").password("123456").roles("VIP3","VIP2")
                .and()
                .withUser("wangwu").password("123456").roles("VIP3","VIP1");
    }

该种方法是将用户保存在内存中,项目中应该使用数据库,如下:

  @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("select username,password, enabled from users where username = ?")
                .authoritiesByUsernameQuery("select username, role from user_roles where username = ?");
    }

此时不同用户就拥有了不同权限,如zhangsan只能访问普通和高级武功秘籍,访问绝世武功秘籍就会提示访问被拒绝:



⑤ 开启自动注销功能http.formLogout()

看源码注释:

/**
   * Provides logout support. This is automatically applied when using
   * {@link WebSecurityConfigurerAdapter}.
   * // 提供了注销支持。这种能力是自动被应用的当使用了WebSecurityConfigurerAdapter。
   *  The default is that accessing the URL
   * "/logout" will log the user out by invalidating the HTTP Session, cleaning up any
   * {@link #rememberMe()} authentication that was configured, clearing the
   * {@link SecurityContextHolder}, and then redirect to "/login?success".
   *// 默认应用于/logout请求,删除会话session,清除rememberMe权限配置并重定向到/login?success请求。
   * <h2>Example Custom Configuration</h2>
   *
   * The following customization to log out when the URL "/custom-logout" is invoked.
   * Log out will remove the cookie named "remove", not invalidate the HttpSession,
   * clear the SecurityContextHolder, and upon completion redirect to "/logout-success".
   *
   * <pre>
   * &#064;Configuration
   * &#064;EnableWebSecurity
   * public class LogoutSecurityConfig extends WebSecurityConfigurerAdapter {
   *
   *  &#064;Override
   *  protected void configure(HttpSecurity http) throws Exception {
   *    http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin()
   *        .and()
   *        // sample logout customization
   *        .logout().deleteCookies(&quot;remove&quot;).invalidateHttpSession(false)
   *        .logoutUrl(&quot;/custom-logout&quot;).logoutSuccessUrl(&quot;/logout-success&quot;);
   *  }
   *
   *  &#064;Override
   *  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   *    auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;);
   *  }
   * }
   * </pre>
   *
   * @return
   * @throws Exception
   */
  public LogoutConfigurer<HttpSecurity> logout() throws Exception {
    return getOrApply(new LogoutConfigurer<HttpSecurity>());
  }

修改请求访问规则配置方法如下:

  @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 定制请求的授权规则
        http.authorizeRequests()
            .antMatchers("/css/**", "/").permitAll()
            .antMatchers("/level1/**").hasRole("VIP1")
            .antMatchers("/level2/**").hasRole("VIP2")
            .antMatchers("/level3/**").hasRole("VIP3");
        // 开启自动配置的登录功能
        http.formLogin();
        // 开启自动配置的注销功能
        http.logout();
    }



在欢迎页面添加注销表单:


点击注销效果如下(重定向到了/login?logout):


修改默认退出重定向页面:

// 开启自动配置的注销功能,默认重定向到/logout?success,修改为"/"
http.logout().logoutSuccessUrl("/");


此时退出返回到主页面!


【4】Thymeleaf提供的SpringSecurity标签支持

需要引入thymeleaf-extras-springsecurity4,修改默认引入的Thymeleaf版本:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
    <thymeleaf-layout-dialect.version>2.3.0</thymeleaf-layout-dialect.version>
    <thymeleaf-extras-springsecurity4.version>3.0.2.RELEASE</thymeleaf-extras-springsecurity4.version>
  </properties>
dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-springsecurity</artifactId>
</dependency>

页面引入security的名称空间:

<html xmlns:th="http://www.thymeleaf.org"
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

① 测试一,修改默认访问页面提示

修改默认访问页面如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">欢迎光临武林秘籍管理系统</h1>
<!--如果没有认证,则显示如下-->
<div sec:authorize="!isAuthenticated()">
  <h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/login}">请登录</a></h2>
</div>
<!--如果认证了,则显示如下-->
<div sec:authorize="isAuthenticated()">
  <h2><span sec:authentication="name"></span>,您好,您的角色有:<span sec:authentication="principal.authorities"></span></h2>
  <form th:action="@{/logout}" method="post">
    <input type="submit" value="注销"/>
  </form>
</div>

没有认证时访问首页如下:



登录成功后,首页显示如下:



② 测试二,不同权限显示不同武林秘籍

修改页面如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">欢迎光临武林秘籍管理系统</h1>
<!--如果没有认证,则显示如下-->
<div sec:authorize="!isAuthenticated()">
  <h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/login}">请登录</a></h2>
</div>
<!--如果认证了,则显示如下-->
<div sec:authorize="isAuthenticated()">
  <h2><span sec:authentication="name"></span>,您好,您的角色有:<span sec:authentication="principal.authorities"></span></h2>
  <form th:action="@{/logout}" method="post">
    <input type="submit" value="注销"/>
  </form>
</div>
<hr>
<div sec:authorize="hasRole('VIP1')">
<h3>普通武功秘籍</h3>
<ul>
  <li><a th:href="@{/level1/1}">罗汉拳</a></li>
  <li><a th:href="@{/level1/2}">武当长拳</a></li>
  <li><a th:href="@{/level1/3}">全真剑法</a></li>
</ul>
</div>
<div sec:authorize="hasRole('VIP2')">
<h3>高级武功秘籍</h3>
<ul>
  <li><a th:href="@{/level2/1}">太极拳</a></li>
  <li><a th:href="@{/level2/2}">七伤拳</a></li>
  <li><a th:href="@{/level2/3}">梯云纵</a></li>
</ul>
</div>
<div sec:authorize="hasRole('VIP3')">
<h3>绝世武功秘籍</h3>
<ul>
  <li><a th:href="@{/level3/1}">葵花宝典</a></li>
  <li><a th:href="@{/level3/2}">龟派气功</a></li>
  <li><a th:href="@{/level3/3}">独孤九剑</a></li>
</ul>
</div>
</body>
</html>

没有登录时,显示效果如下:


登录后显示效果如下:

只显示拥有的权限目录!


【5】常见功能-Remeber me

配置启用remember-me功能

  @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 定制请求的授权规则
        http.authorizeRequests()
            .antMatchers("/css/**", "/").permitAll()
            .antMatchers("/level1/**").hasRole("VIP1")
            .antMatchers("/level2/**").hasRole("VIP2")
            .antMatchers("/level3/**").hasRole("VIP3");
        // 开启自动配置的登录功能
        http.formLogin();
        // 开启自动配置的注销功能,默认重定向到/logout?success,修改为"/"
        http.logout().logoutSuccessUrl("/");
        //开启自动配置的Remember me
        http.rememberMe();
    }



此时登录页显示如下:



点击登录,查看network :




image.jpeg



此时关闭浏览器,再次打开,直接进入登录后的页面:



点击注销,将会从浏览器删除该Cookie!



【6】自定义登录页与Remember-me

① 自定义登录页面

修改配置如下:

  @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 定制请求的授权规则
        http.authorizeRequests()
            .antMatchers("/css/**", "/").permitAll()
            .antMatchers("/level1/**").hasRole("VIP1")
            .antMatchers("/level2/**").hasRole("VIP2")
            .antMatchers("/level3/**").hasRole("VIP3");
        // 开启自动配置的登录功能
        http.formLogin().loginPage("/userlogin");
        // 开启自动配置的注销功能,默认重定向到/logout?success,修改为"/"
        http.logout().logoutSuccessUrl("/");
        //开启自动配置的Remember me
        http.rememberMe();
    }

修改自定义登录页面如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
  <h1 align="center">欢迎登陆武林秘籍管理系统</h1>
  <hr>
  <div align="center">
    <form th:action="@{/userlogin}" method="post">
      用户名:<input name="username"/><br>
      密&nbsp;&nbsp;&nbsp;码:<input name="password"><br/>
      <input type="submit" value="登陆">
    </form>
  </div>
</body>
</html>

访问受保护的页面或者点击登录时,会来到我们自定义的登录页面:


FormLoginConfigurer.loginPage方法源码与注释如下:

/**
   * <p>
   * Specifies the URL to send users to if login is required. 
   * 发送给用户的登录请求
   * If used with
   * {@link WebSecurityConfigurerAdapter} a default login page will be generated when
   * this attribute is not specified.
   * 如果没有被指定则使用默认的登录页面
   * </p>
   *
   * <p>
   * If a URL is specified or this is not being used in conjuction with
   * {@link WebSecurityConfigurerAdapter}, users are required to process the specified
   * URL to generate a login page. 
   * 如果url被指定或没有使用默认的登录页面,用户需要处理登录请求跳转到登录页面
   * In general, the login page should create a form that
   * submits a request with the following requirements to work with
   * {@link UsernamePasswordAuthenticationFilter}:
   * // 一般来说,登录页面需要创建一个表单提交如下所需的参数属性:
   * </p>
   *
   * <ul>
   * <li>It must be an HTTP POST</li>
   * <li>It must be submitted to {@link #loginProcessingUrl(String)}</li>
   * <li>It should include the username as an HTTP parameter by the name of
   * {@link #usernameParameter(String)}</li>
   * <li>It should include the password as an HTTP parameter by the name of
   * {@link #passwordParameter(String)}</li>
   * </ul>
   *
   * <h2>Example login.jsp</h2>
   *
   * Login pages can be rendered with any technology you choose so long as the rules
   * above are followed. Below is an example login.jsp that can be used as a quick start
   * when using JSP's or as a baseline to translate into another view technology.
   *下面是一个JSP例子,可以被用来快速创建登录页。
   * <pre>
   * <!-- loginProcessingUrl should correspond to FormLoginConfigurer#loginProcessingUrl. Don't forget to perform a POST -->
   * &lt;c:url value="/login" var="loginProcessingUrl"/&gt;
   * &lt;form action="${loginProcessingUrl}" method="post"&gt;
   *    &lt;fieldset&gt;
   *        &lt;legend&gt;Please Login&lt;/legend&gt;
   *        &lt;!-- use param.error assuming FormLoginConfigurer#failureUrl contains the query parameter error --&gt;
   *        &lt;c:if test="${param.error != null}"&gt;
   *            &lt;div&gt;
   *                Failed to login.
   *                &lt;c:if test="${SPRING_SECURITY_LAST_EXCEPTION != null}"&gt;
   *                  Reason: &lt;c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" /&gt;
   *                &lt;/c:if&gt;
   *            &lt;/div&gt;
   *        &lt;/c:if&gt;
   *        &lt;!-- the configured LogoutConfigurer#logoutSuccessUrl is /login?logout and contains the query param logout --&gt;
   *        &lt;c:if test="${param.logout != null}"&gt;
   *            &lt;div&gt;
   *                You have been logged out.
   *            &lt;/div&gt;
   *        &lt;/c:if&gt;
   *        &lt;p&gt;
   *        &lt;label for="username"&gt;Username&lt;/label&gt;
   *        &lt;input type="text" id="username" name="username"/&gt;
   *        &lt;/p&gt;
   *        &lt;p&gt;
   *        &lt;label for="password"&gt;Password&lt;/label&gt;
   *        &lt;input type="password" id="password" name="password"/&gt;
   *        &lt;/p&gt;
   *        &lt;!-- if using RememberMeConfigurer make sure remember-me matches RememberMeConfigurer#rememberMeParameter --&gt;
   *        &lt;p&gt;
   *        &lt;label for="remember-me"&gt;Remember Me?&lt;/label&gt;
   *        &lt;input type="checkbox" id="remember-me" name="remember-me"/&gt;
   *        &lt;/p&gt;
   *        &lt;div&gt;
   *            &lt;button type="submit" class="btn"&gt;Log in&lt;/button&gt;
   *        &lt;/div&gt;
   *    &lt;/fieldset&gt;
   * &lt;/form&gt;
   * </pre>
   *
   * <h2>Impact on other defaults</h2>
   *
   * Updating this value, also impacts a number of other default values.
   * // 更新默认值,将会影响其他默认值
   * For example,
   * the following are the default values when only formLogin() was specified.
   *// 下面是当formLogin被开启时一系列默认值
   * <ul>
   * <li>/login GET - the login form</li>
   * <li>/login POST - process the credentials and if valid authenticate the user</li>
   * <li>/login?error GET - redirect here for failed authentication attempts</li>
   * <li>/login?logout GET - redirect here after successfully logging out</li>
   * </ul>
   *
   * If "/authenticate" was passed to this method it update the defaults as shown below:
   *
   * <ul>
   * <li>/authenticate GET - the login form</li>
   * <li>/authenticate POST - process the credentials and if valid authenticate the user
   * </li>
   * <li>/authenticate?error GET - redirect here for failed authentication attempts</li>
   * <li>/authenticate?logout GET - redirect here after successfully logging out</li>
   * </ul>
   *
   *
   * @param loginPage the login page to redirect to if authentication is required (i.e.
   * "/login")
   * @return the {@link FormLoginConfigurer} for additional customization
   */
  @Override
  public FormLoginConfigurer<H> loginPage(String loginPage) {
    return super.loginPage(loginPage);
  }

通过阅读上述源码,我们尝试修改用户名、密码默认参数名如下:

  • 修改配置类
@Override
    protected void configure(HttpSecurity http) throws Exception {
        // 定制请求的授权规则
        http.authorizeRequests()
            .antMatchers("/css/**", "/").permitAll()
            .antMatchers("/level1/**").hasRole("VIP1")
            .antMatchers("/level2/**").hasRole("VIP2")
            .antMatchers("/level3/**").hasRole("VIP3");
        // 开启自动配置的登录功能
        http.formLogin().usernameParameter("name").passwordParameter("pwd").loginPage("/userlogin");
        // 开启自动配置的注销功能,默认重定向到/logout?success,修改为"/"
        http.logout().logoutSuccessUrl("/");
        //开启自动配置的Remember me
        http.rememberMe();
    }
  • 修改表单
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
  <h1 align="center">欢迎登陆武林秘籍管理系统</h1>
  <hr>
  <div align="center">
    <form th:action="@{/userlogin}" method="post">
      用户名:<input name="name"/><br>
      密&nbsp;&nbsp;&nbsp;码:<input name="pwd"><br/>
      <input type="submit" value="登陆">
    </form>
  </div>
</body>
</html>

再次测试登录:

成功登录!


② 为自定义登录页面添加Remember-me

首先查看使用默认登录页面时remember-me的源码:


可以看到,添加了一个复选框,name为"remember-me"。

同样,在我们的登录表单中,也添加该复选框即可!

修改表单如下:

<form th:action="@{/userlogin}" method="post">
  用户名:<input name="name"/><br>
  密&nbsp;&nbsp;&nbsp;码:<input name="pwd"><br/>
  <input type="submit" value="登陆">
  <input type="checkbox" name="remember-me"/> Remember-me
</form>

登录测试如下图:


同样可以查看RememberMeConfigurer源码获取记住我的默认name:

public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
    extends AbstractHttpConfigurer<RememberMeConfigurer<H>, H> {
  /**
   * The default name for remember me parameter name and remember me cookie name
   */
  private static final String DEFAULT_REMEMBER_ME_NAME = "remember-me";
  private AuthenticationSuccessHandler authenticationSuccessHandler;
  private String key;
  private RememberMeServices rememberMeServices;
  private LogoutHandler logoutHandler;
  private String rememberMeParameter = DEFAULT_REMEMBER_ME_NAME;
  private String rememberMeCookieName = DEFAULT_REMEMBER_ME_NAME;
  private String rememberMeCookieDomain;
  private PersistentTokenRepository tokenRepository;
  private UserDetailsService userDetailsService;
  private Integer tokenValiditySeconds;
  private Boolean useSecureCookie;
  private Boolean alwaysRemember;
  //...
}

也可以使用自定义记住我name:

  • 配置方法修改
  //开启自动配置的Remember me,并修改记住我的参数name
  http.rememberMe().rememberMeParameter("remember");
  • 表单修改
<form th:action="@{/userlogin}" method="post">
  用户名:<input name="name"/><br>
  密&nbsp;&nbsp;&nbsp;码:<input name="pwd"><br/>
  <input type="checkbox" name="remember"/> Remember-me<br/>
  <input type="submit" value="登陆">
</form>

【7】CSRF

CSRF(Cross-site request forgery)跨站请求伪造。

HttpSecurity默认启用csrf功能,会为表单添加_csrf的值,提交携带来预防CSRF。

如点击登录,查看network:


目录
相关文章
|
6天前
|
存储 安全 Java
SpringBoot搭建Spring Security 入门
SpringBoot搭建Spring Security 入门
121 0
|
6天前
|
存储 安全 Java
Spring Boot整合Spring Security--学习笔记
Spring Boot整合Spring Security--学习笔记
62 1
|
6天前
|
前端开发 安全 Java
SpringBoot 实现登录验证码(附集成SpringSecurity)
SpringBoot 实现登录验证码(附集成SpringSecurity)
|
6天前
|
安全 数据安全/隐私保护
Springboot+Spring security +jwt认证+动态授权
Springboot+Spring security +jwt认证+动态授权
|
6月前
|
安全 前端开发 Java
微服务技术系列教程(38)- SpringBoot -整合SpringSecurity
微服务技术系列教程(38)- SpringBoot -整合SpringSecurity
70 0
|
6月前
|
安全 Java 数据安全/隐私保护
微服务技术系列教程(37)- SpringBoot -SpringSecurity简介
微服务技术系列教程(37)- SpringBoot -SpringSecurity简介
43 0
|
6天前
|
前端开发 JavaScript Java
基于Springboot+SpringSecurity+Activiti7实现的工作流系统可方便二次开发(附完整源码)
基于Springboot+SpringSecurity+Activiti7实现的工作流系统可方便二次开发(附完整源码)
74 0
|
8月前
|
XML 安全 Java
Spring Boot 中的 Spring Security 是什么,如何使用
Spring Boot 中的 Spring Security 是什么,如何使用
|
6天前
|
安全 Java Spring
springboot整合spring security 实现用户登录注册与鉴权全记录
【1月更文挑战第11天】springboot整合spring security 实现用户登录注册与鉴权全记录
127 2
|
6天前
|
安全 Java Spring
springboot整合spring security 安全认证框架
springboot整合spring security 安全认证框架