传统的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;
}
}