SpringSecurity实现记住我功能

传统的web实现

创建一个SpringBoot的项目

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

编写application.properties文件

# thymeleaf的配置
spring.thymeleaf.cache=false
# thymeleaf的默认配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
# 调整 session 过期时间
server.servlet.session.timeout=1

编写templates中的login.html页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>用户登录</h1>
<form method="post" th:action="@{doLogin}">
    用户名:<input name="uname" type="text"><br/>
    密码:<input name="passwd" type="password"><br/>
    <!--  value 可选值默认为: true  yes  on  1 都可以-->
    记住我:<input name="remember-me" type="checkbox" value="true"><br/>
    <input type="submit" value="登录">
</form>
<h3>
    <div th:text="${session.SPRING_SECURITY_LAST_EXCEPTION}"></div>
</h3>
</body>
</html>

编写控制层的代码

@RestController
public class IndexController {
    @GetMapping("/")
    public String index(HttpServletRequest request) {
        System.out.println("hello!");
        return "hello";
    }
}

编写config包下的WebMvcConfig

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 如果要访问login.html,则就输入login.html即可,会自动帮你找templates中的login.html页面
        registry.addViewController("login.html").setViewName("login");
    }
}

编写config包下的WebSecurityConfig

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // 自定义数据源
    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("admin").build());
        return inMemoryUserDetailsManager;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());	// 指定自定义的数据源
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/login.html").permitAll()   // 不放行的话,会被 mvcConfig拦截,会报错
                .anyRequest().authenticated()	// 认证所有的请求
                .and()
                .formLogin()
                .loginPage("/login.html")  // 这里使用Web MvcConfig的映射,这里的login.html并不是页面,而是访问路径
                .loginProcessingUrl("/doLogin")	// action的路径
                .usernameParameter("uname")		// 自定义input表单的name属性
                .passwordParameter("passwd")	// 自定义input表单的name属性
                .defaultSuccessUrl("/", true)	// 登录成功后始终跳转到此映射路径。
                .and()
                .rememberMe()   // 开启记住我
                //.rememberMeParameter("remember")    // 修改记住我的参数,默认是 remember-me
                //.alwaysRemember(true)   // 总是记住我
                .and()
                .csrf().disable();
    }
}

前后端分离实现

创建一个SpringBoot项目

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

编写控制层

@RestController
public class TestController {
    @GetMapping("/test")
    public String test() {
        System.out.println("test ok!");
        return "test ok!";
    }
}

编写config包下自定义的Filter

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
public class LoginFilter extends UsernamePasswordAuthenticationFilter 
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        System.out.println(request.getMethod());
        // 1. 判断是否是post请求方式
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        // 2. 判断是否是json格式请求方式
        if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
            // 3. 从 json 数据中获取用户输入用户名和密码进行认证{"uname":"xxx","password":"xxx","remember-me":"xxx"}
            // 将json格式序列化 ----> 转换为对象
            try {
                Map<String, String> userInfo = new ObjectMapper().readValue(request.getInputStream(), Map.class);
                String userName = userInfo.get(getUsernameParameter());
                String passwd = userInfo.get(getPasswordParameter());
                String rememberValue = userInfo.get(AbstractRememberMeServices.DEFAULT_PARAMETER);  // 这里可以自定义 记住我的参数
                if (!ObjectUtils.isEmpty(rememberValue)) {
                    request.setAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER, rememberValue);
                }
                System.out.println("用户名:" + userName + "     密码: " + passwd + "    是否记住我:" + rememberValue);
                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, passwd);
                setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return super.attemptAuthentication(request, response);
    }
}

编写config包下的 自定义实现我的services实现类

import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.servlet.http.HttpServletRequest;
public class MyPersistentTokenBasedRememberMeServices extends PersistentTokenBasedRememberMeServices {

    public MyPersistentTokenBasedRememberMeServices(String key, UserDetailsService userDetailsService, PersistentTokenRepository tokenRepository) {
        super(key, userDetailsService, tokenRepository);
    }

    /**
     * 自定义前后端分离, 获取 remember-me 方式
     *
     * @param request
     * @param parameter
     * @return
     */
    @Override
    protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
        String rememberValue = null;
        if (request.getAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER) != null) {
            rememberValue = request.getAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER).toString();
        }
        if (rememberValue != null) {
            if (rememberValue.equalsIgnoreCase("true") || rememberValue.equalsIgnoreCase("on")
                    || rememberValue.equalsIgnoreCase("yes") || rememberValue.equalsIgnoreCase("1")) {
                return true;
            }
        }
        return false;
    }
}

编写config包下的SecurityConfig类

public class MyPersistentTokenBasedRememberMeServices extends PersistentTokenBasedRememberMeServices {

    public MyPersistentTokenBasedRememberMeServices(String key, UserDetailsService userDetailsService, PersistentTokenRepository tokenRepository) {
        super(key, userDetailsService, tokenRepository);
    }

    /**
     * 自定义前后端分离, 获取 remember-me 方式
     *
     * @param request
     * @param parameter
     * @return
     */
    @Override
    protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
        String rememberValue = null;
        if (request.getAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER) != null) {
            rememberValue = request.getAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER).toString();
        }
        if (rememberValue != null) {
            if (rememberValue.equalsIgnoreCase("true") || rememberValue.equalsIgnoreCase("on")
                    || rememberValue.equalsIgnoreCase("yes") || rememberValue.equalsIgnoreCase("1")) {
                return true;
            }
        }
        return false;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

☞^O^☜♞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值