1、功能实现
1.自定义登录成功、登录失败处理程序
2.自定义匿名访问无权、已认证无权访问处理程序
3.自定义记住我认证、退出登录成功处理程序
2、security05 子工程
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yzm</groupId>
<artifactId>security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>security05</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>security05</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>com.yzm</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.192.128:3306/testdb?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
username: root
password: 1234
main:
allow-bean-definition-overriding: true
mybatis-plus:
mapper-locations: classpath:/mapper/*Mapper.xml
type-aliases-package: com.yzm.security05.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
login.thml 页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录页</title>
</head>
<body>
<h1 th:if="${param.logout}">You have been logged out.</h1>
<h1 th:if="${param.error}">You username or password is wrong</h1>
<h1 th:if="${param.authentication}">Full authentication is required to access this resource</h1>
<h2>用户名密码登录</h2>
<form action="/login" method="post">
<p>
<label for="username">Username</label>
<input type="text" id="username" name="username" placeholder="Username">
</p>
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password" placeholder="Password">
</p>
<p>
<label>
<input type="checkbox" name="remember-me">
</label> Remember me on this computer.
</p>
<button type="submit">Sign in</button>
</form>
</body>
</html>
3、登录成功、登录失败
package com.yzm.security05.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录成功后进行业务处理
* Security默认是跳转 /
*/
@Slf4j
public class SecLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
log.info("登录成功");
// 重定向到/home
response.sendRedirect(request.getContextPath() + "/home");
}
}
package com.yzm.security05.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录失败后进行业务处理
*/
@Slf4j
public class SecLoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.info("登录失败:" + exception.getMessage());
// 重定向到登录页
response.sendRedirect(request.getContextPath() + "/auth/login?error");
}
}
在SecurityConfig#configure
//配置资源权限规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 关闭CSRF跨域
.csrf().disable()
// 登录
.formLogin()
.loginPage("/auth/login") //指定登录页的路径,默认/login
.loginProcessingUrl("/login") //指定自定义form表单请求的路径(必须跟login.html中的form action=“url”一致)
//.defaultSuccessUrl("/home", true) // 登录成功后的跳转url地址,默认是 "/"
//.failureUrl("/auth/login?error") // 登录失败后的跳转url地址,默认是 "/login?error"
.successHandler(new SecLoginSuccessHandler())
.failureHandler(new SecLoginFailureHandler())
.permitAll()
.and()
...
// 访问路径URL的授权策略,如注册、登录免登录认证等
.authorizeRequests()
.antMatchers("/", "/home", "/register", "/auth/login").permitAll() //指定url放行
.antMatchers("/hello").rememberMe()
.anyRequest().authenticated() //其他任何请求都需要身份认证
;
}
启动项目,登录时输入错误的密码
然后再输入正确的密码
4、匿名无权访问、认证后无权访问
package com.yzm.security05.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 匿名用户访问无权限资源时的异常
*/
@Slf4j
public class SecAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
log.info("需要登录");
response.sendRedirect(request.getContextPath() + "/auth/login?authentication");
}
}
package com.yzm.security05.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 认证过的用户访问无权限资源时的异常
*/
@Slf4j
public class SecAccessDeniedHandler extends AccessDeniedHandlerImpl {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.info("授权失败:" + accessDeniedException.getMessage());
// 重定向到登录页
response.sendRedirect(request.getContextPath() + "/401");
}
}
在SecurityConfig#configure
//配置资源权限规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
// 登录
.formLogin()
.loginPage("/auth/login") //指定登录页的路径,默认/login
.loginProcessingUrl("/login") //指定自定义form表单请求的路径(必须跟login.html中的form action=“url”一致)
//.defaultSuccessUrl("/home", true) // 登录成功后的跳转url地址,默认是 "/"
//.failureUrl("/auth/login?error") // 登录失败后的跳转url地址,默认是 "/login?error"
.successHandler(new SecLoginSuccessHandler())
.failureHandler(new SecLoginFailureHandler())
.permitAll()
.and()
// 异常处理
.exceptionHandling()
.authenticationEntryPoint(new SecAuthenticationEntryPoint()) // 需要认证
//.accessDeniedPage("/401") // 拒接访问跳转页面
.accessDeniedHandler(new SecAccessDeniedHandler()) // 授权失败
.and()
// 访问路径URL的授权策略,如注册、登录免登录认证等
.authorizeRequests()
.antMatchers("/", "/home", "/register", "/auth/login").permitAll() //指定url放行
.antMatchers("/hello").rememberMe()
.anyRequest().authenticated() //其他任何请求都需要身份认证
;
}
重启项目,访问/home
访问权限接口
登录yzm,访问/admin/**
5、记住我认证、退出成功
package com.yzm.security05.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 记住我认证成功处理
*/
@Slf4j
public class SecAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
log.info("使用记住我功能,认证成功:" + authentication.getPrincipal());
}
}
package com.yzm.security05.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 退出登录成功后进行业务处理
*/
@Slf4j
public class SecLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (principal instanceof User) {
String username = ((User) principal).getUsername();
log.info("退出成功,用户名:{}", username);
}
}
// 重定向到登录页
response.sendRedirect(request.getContextPath() + "/auth/login?logout");
}
}
在SecurityConfig#configure
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
// 自动登录
.rememberMe()
.tokenValiditySeconds(120)
.authenticationSuccessHandler(new SecAuthenticationSuccessHandler())
.and()
// 退出登录
.logout().permitAll()
.deleteCookies("JSESSIONID")
//.logoutSuccessUrl("/auth/login?logout") // 默认是 "/login?logout"
.logoutSuccessHandler(new SecLogoutSuccessHandler())
.permitAll()
.and()
...
;
}
重启,登录yzm,选中记住我,然后关闭浏览器,重开浏览器。访问 /home
点击注销