赞
踩
目录
本篇文章从方面进行讲解 :
AbstractUserDetailsAuthenticationProvider类中authenticate⽅法在最后认证成功之后实现了记住我功能,但是查看源码得知如果开启记住我,必须进⾏相关的设置。
通过对源码的分析得出自定义的实现方式:
通过源码分析得知必须在认证请求中加⼊参数remember-me值为"true,on,yes,1"其中任意⼀个才可以完成记住我功能,这个时候修改认证界⾯:
- <!DOCTYPE html>
- <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
- <head>
- <meta charset="UTF-8">
- <title>登录页面</title>
- </head>
- <body>
- <form action="/doLogin" method="post">
- 用户名:<input type="text" name="uName" /></br>
- 密码: <input type="password" name="pwdsss">
- 是否记住我 : <input type="checkbox" name="remember-me" value="true"/>
- <input type="submit" value="提交">
- </form>
- </body>
-
- </html>
配置中开启记住我
- @Configuration(proxyBeanMethods = false)
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
-
-
- /**
- * 自定义数据源
- * @return
- */
- @Override
- @Bean
- public UserDetailsService userDetailsService(){
- UserDetails userDetails = User.withUsername("zs").password("{noop}123").roles("admin").build();
- InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
- inMemoryUserDetailsManager.createUser(userDetails);
- return inMemoryUserDetailsManager;
- }
-
- /**
- * 定义安全规则
- */
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.authorizeRequests()
- .mvcMatchers("/login.html").permitAll()
- .anyRequest().authenticated()
- .and()
- .rememberMe()// 开启记住我
- .and()
- .formLogin()
- .loginPage("/login.html")
- .loginProcessingUrl("/doLogin")
- .failureForwardUrl("/login.html")
- .usernameParameter("uName")
- .passwordParameter("pwdsss")
- .and()
- .csrf()
- .disable();
- }
- }
- package com.bjpowenrode.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.stereotype.Component;
- import org.springframework.util.ObjectUtils;
- import org.springframework.util.StringUtils;
-
- import javax.servlet.ServletInputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.util.Map;
-
- import static org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
-
- /**
- * @author 千城丶Y
- * @className : LoginFilter
- * @date : 2022/9/3 14:50
- * @Description TODO 自定义前后端登录验证的Filter
- */
- public class LoginFilter extends UsernamePasswordAuthenticationFilter {
-
- private String passwordParameter =SPRING_SECURITY_FORM_PASSWORD_KEY;
- private String usernameParameter =SPRING_SECURITY_FORM_USERNAME_KEY;
- private String rememberMeParameter = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY ;
-
-
- /**
- * 重写获取用户信息的方法
- */
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
- if (!request.getMethod().equals("POST")) {
- throw new AuthenticationServiceException(
- "Authentication method not supported: " + request.getMethod());
- }
-
- try {
- //2.判断是否是 json 格式请求类型
- if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
- // 获取JSON 流数据
- ServletInputStream inputStream = request.getInputStream();
- Map<String,String> map = new ObjectMapper().readValue(inputStream, Map.class);
-
- // 获取用户名
-
- String userName = map.get( usernameParameter);
- String pwd = map.get(passwordParameter);
- String rememberMe = map.get(rememberMeParameter);
-
- if (StringUtils.isEmpty(userName)){
- userName = "";
- }
- if (StringUtils.isEmpty(pwd)){
- pwd = "";
- }
-
- if (!ObjectUtils.isEmpty(rememberMe)){
- request.setAttribute(rememberMeParameter,rememberMe);
- }
-
- UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
- userName, pwd);
-
- // Allow subclasses to set the "details" property
- setDetails(request, authRequest);
-
- return this.getAuthenticationManager().authenticate(authRequest);
- }else {
- throw new AuthenticationServiceException("认证参数格式不正确!");
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override
- public void setPasswordParameter(String passwordParameter) {
- this.passwordParameter = passwordParameter;
- }
-
- @Override
- public void setUsernameParameter(String usernameParameter) {
- this.usernameParameter = usernameParameter;
- }
-
- public void setRememberMeParameter(String rememberMeParameter) {
- this.rememberMeParameter = rememberMeParameter;
- }
- }
- package com.bjpowenrode.service;
-
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
- import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
-
- import javax.servlet.http.HttpServletRequest;
-
- /**
- * @author 千城丶Y
- * @className : My
- * @date : 2022/9/3 15:20
- * @Description TODO 自定义 RememberMeService
- */
- public class MyPersistentTokenBasedRememberMeServices extends PersistentTokenBasedRememberMeServices {
-
- private boolean alwaysRemember;
- public MyPersistentTokenBasedRememberMeServices(String key, UserDetailsService userDetailsService, PersistentTokenRepository tokenRepository) {
- super(key, userDetailsService, tokenRepository);
- }
-
- @Override
- protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
- if (alwaysRemember) {
- return true;
- }
- // 这里修改为从 请求作用域中获取
- String paramValue = request.getAttribute(parameter).toString();
- if (paramValue != null) {
- if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on")
- || paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
- return true;
- }
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Did not send remember-me cookie (principal did not set parameter '"
- + parameter + "')");
- }
-
- return false;
- }
-
- public boolean isAlwaysRemember() {
- return alwaysRemember;
- }
-
- @Override
- public void setAlwaysRemember(boolean alwaysRemember) {
- this.alwaysRemember = alwaysRemember;
- }
- }
- package com.bjpowenrode.config;
-
- import com.bjpowenrode.filter.LoginFilter;
- import com.bjpowenrode.service.MyPersistentTokenBasedRememberMeServices;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.http.HttpMethod;
- import org.springframework.http.HttpStatus;
- import org.springframework.http.MediaType;
- import org.springframework.security.authentication.AuthenticationManager;
- 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.WebSecurityConfigurerAdapter;
- import org.springframework.security.core.userdetails.User;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.provisioning.InMemoryUserDetailsManager;
- import org.springframework.security.web.authentication.RememberMeServices;
- import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
- import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
- import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
- import org.springframework.security.web.util.matcher.OrRequestMatcher;
-
- import java.util.HashMap;
- import java.util.Map;
- import java.util.UUID;
-
- /**
- * @author 千城丶Y
- * @className : WebSecurityConfig
- * @date : 2022/9/3 14:47
- * @Description TODO 安全认证类
- */
- @Configuration(proxyBeanMethods = true) // 这里如果是 false 则每次使用bean 时都会新建
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
-
- /**
- * 自定义数据源
- */
- @Override
- @Bean
- public UserDetailsService userDetailsService(){
- InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
- inMemoryUserDetailsManager.createUser(User.withUsername("zs").password("{noop}123").roles("admin").build());
- return inMemoryUserDetailsManager;
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(userDetailsService());
- }
-
- /**
- * 暴露本地AuthenticationManagerBuilder
- */
- @Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
-
- /**
- * 导入自定义Filter
- */
- @Bean
- public LoginFilter loginFilter () throws Exception {
- LoginFilter loginFilter = new LoginFilter();
- loginFilter.setUsernameParameter("userName");
- loginFilter.setPasswordParameter("pwd");
- loginFilter.setFilterProcessesUrl("/doLogin");
-
- loginFilter.setAuthenticationManager(authenticationManagerBean());
- loginFilter.setRememberMeServices(rememberMeServices()); // 设置 认证成功时使用自定义rememberMeService 认证成功后 生成cookie 的
- loginFilter.setAuthenticationSuccessHandler(
- (request,response,authentication)->{
- Map<String,Object> result = new HashMap<>(3);
- result.put("msg","登录成功!");
- result.put("code",200);
- result.put("authen",authentication);
-
- ObjectMapper objectMapper = new ObjectMapper();
- String json = objectMapper.writeValueAsString(result);
- response.setStatus(HttpStatus.OK.value());
- response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
- response.getWriter().println(json);
-
- }
- );
- loginFilter.setAuthenticationFailureHandler((request,response,authentication)->{
- Map<String,Object> result = new HashMap<>(3);
- result.put("msg","登录失败!");
- result.put("code",500);
- result.put("authen",authentication);
-
- ObjectMapper objectMapper = new ObjectMapper();
- String json = objectMapper.writeValueAsString(result);
- response.setStatus(HttpStatus.NO_CONTENT.value());
- response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
- response.getWriter().println(json);
-
- });
- return loginFilter ;
- }
-
- /**
- * 自定义安全
- */
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.authorizeRequests()
- .mvcMatchers("/doLogin").permitAll()
- .anyRequest().authenticated()
- .and()
- .exceptionHandling()
- .authenticationEntryPoint((request,response,exception)->{
- Map<String,Object> result = new HashMap<>(3);
- result.put("msg","未登录!");
- result.put("code",401);
- result.put("error",exception.getMessage());
-
- ObjectMapper objectMapper = new ObjectMapper();
- String json = objectMapper.writeValueAsString(result);
- response.setStatus(HttpStatus.EXPECTATION_FAILED.value());
- response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
- response.getWriter().println(json);
- })
- .and()
- .formLogin()
- .usernameParameter("userName")
- .passwordParameter("pwd")
- .loginProcessingUrl("/doLogin")
- .successHandler((request,response,authentication)->{
- Map<String,Object> result = new HashMap<>(3);
- result.put("msg","登录成功!");
- result.put("code",200);
- result.put("authen",authentication);
-
- ObjectMapper objectMapper = new ObjectMapper();
- String json = objectMapper.writeValueAsString(result);
- response.setStatus(HttpStatus.OK.value());
- response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
- response.getWriter().println(json);
-
- })
- .failureHandler((request,response,authentication)->{
- Map<String,Object> result = new HashMap<>(3);
- result.put("msg","登录失败!");
- result.put("code",500);
- result.put("authen",authentication);
-
- ObjectMapper objectMapper = new ObjectMapper();
- String json = objectMapper.writeValueAsString(result);
- response.setStatus(HttpStatus.NO_CONTENT.value());
- response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
- response.getWriter().println(json);
-
- })
- .and()
- .rememberMe()
- .rememberMeServices(rememberMeServices()) // 设置自动登录时使用rememberService
- .and()
- .logout()
- .logoutRequestMatcher(new OrRequestMatcher(
- new AntPathRequestMatcher("/logout", HttpMethod.GET.name()),
- new AntPathRequestMatcher("/logout",HttpMethod.POST.name())
- ))
- .logoutSuccessHandler((res,resp,authentication)->{
- Map<String,Object> rs = new HashMap<>();
- rs.put("msg","退出登录成功");
- rs.put("用户信息",authentication);
- resp.setStatus(HttpStatus.OK.value());
- String json = new ObjectMapper().writeValueAsString(rs);
-
- resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
-
- resp.getWriter().println(json);
- })
- .and()
- .csrf()
- .disable();
-
- // 替换掉这个Filter
- http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
- }
-
- /**
- * 引入自定义RememberMeService
- */
- @Bean
- public RememberMeServices rememberMeServices(){
- // 这个 如果是用内存的话不能new 需要让他是对象 才可以,不然数据会不一致
- MyPersistentTokenBasedRememberMeServices myPersistentTokenBasedRememberMeServices = new MyPersistentTokenBasedRememberMeServices(UUID.randomUUID().toString(),userDetailsService(),new InMemoryTokenRepositoryImpl());
- return myPersistentTokenBasedRememberMeServices;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。