Security之自定义处理程序篇

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
在这里插入图片描述

点击注销
在这里插入图片描述

相关链接

首页
上一篇:记住我篇
下一篇:会话篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值