Spring Security配置多个数据源并添加登录验证码的实例代码

下面是详细讲解Spring Security配置多个数据源并添加登录验证码的实例代码的完整攻略:

什么是Spring Security?

Spring Security是针对基于Spring的应用程序的安全框架,它提供了一组可以在应用程序中使用的安全服务,例如身份验证和授权。

Spring Security配置多个数据源并添加登录验证码的步骤

第一步:添加依赖和配置类

在项目的pom.xml文件中添加如下依赖:

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

<dependency>
    <groupId>com.github.axet</groupId>
    <artifactId>kaptcha</artifactId>
    <version>0.0.9</version>
</dependency>

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

然后,创建一个安全配置类,实现WebSecurityConfigurerAdapter接口,并在类上添加@Configuration和@EnableWebSecurity注解:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // ...
}

第二步:添加用户和角色

在内存中添加一些用户和角色,以便我们测试安全配置。例如,在SecurityConfig类中添加以下代码:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("user1").password(passwordEncoder().encode("password1")).roles("USER")
            .and()
            .withUser("user2").password(passwordEncoder().encode("password2")).roles("USER")
            .and()
            .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN");
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

第三步:配置多个数据源

配置多个数据源,可以通过重写WebSecurityConfigurerAdapter中的configure(HttpSecurity http)方法来实现。

例如,以下代码演示了如何使用名为dataSource1和dataSource2的两个数据源进行身份验证:

@Autowired
@Qualifier("dataSource1")
private DataSource dataSource1;

@Autowired
@Qualifier("dataSource2")
private DataSource dataSource2;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/user/**").hasRole("USER")
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/home")
            .failureUrl("/login?error=true")
            .successHandler(successHandler())
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login?logout=true")
            .deleteCookies("JSESSIONID")
            .and()
        .csrf()
            .and()
        .exceptionHandling()
            .accessDeniedPage("/403")
            .and()
        .headers()
            .frameOptions().sameOrigin()
            .and()
        .addFilterBefore(validateCodeFilter(), UsernamePasswordAuthenticationFilter.class)
        .addFilterBefore(new DynamicDataSourceFilter(dataSource1, dataSource2), FilterSecurityInterceptor.class);
}

第四步:添加登录验证码

为了添加登录验证码功能,我们需要创建一个验证码生成器和一个过滤器。

首先,创建一个验证码生成器,生成带有数字和字母的随机字符串。

@Bean
public Producer captcha() {
    Properties properties = new Properties();
    properties.setProperty("kaptcha.border", "yes");
    properties.setProperty("kaptcha.border.color", "105,179,90");
    properties.setProperty("kaptcha.textproducer.font.color", "blue");
    properties.setProperty("kaptcha.image.width", "125");
    properties.setProperty("kaptcha.image.height", "45");
    properties.setProperty("kaptcha.textproducer.font.size", "45");
    properties.setProperty("kaptcha.session.key", "code");
    properties.setProperty("kaptcha.textproducer.char.length", "4");
    properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
    Config config = new Config(properties);
    DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
    defaultKaptcha.setConfig(config);
    return defaultKaptcha;
}

然后,创建一个过滤器,验证用户输入的验证码是否正确。

@Component
public class ValidateCodeFilter extends OncePerRequestFilter {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private Producer captchaProducer;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        if ("/login".equalsIgnoreCase(request.getRequestURI()) && "post".equalsIgnoreCase(request.getMethod())) {
            try {
                validate(request);
            } catch (AuthenticationException e) {
                authenticationFailureHandler().onAuthenticationFailure(request, response, e);
                return;
            }
        }
        chain.doFilter(request, response);
    }

    private void validate(HttpServletRequest request) {
        String inputCode = request.getParameter("captcha");
        String code = (String) redisUtils.get("captcha-" + request.getSession().getId());
        if (StringUtils.isBlank(inputCode) || !inputCode.equalsIgnoreCase(code)) {
            throw new AuthenticationServiceException("验证码错误");
        }
    }
}

在SecurityConfig类中,我们添加过滤器并将其添加到UsernamePasswordAuthenticationFilter之前。请注意,我们还添加了一个过滤器,用于基于请求动态切换数据源。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        // ...
        .addFilterBefore(validateCodeFilter(), UsernamePasswordAuthenticationFilter.class)
        .addFilterBefore(new DynamicDataSourceFilter(dataSource1, dataSource2), FilterSecurityInterceptor.class);
}

@Bean
public ValidateCodeFilter validateCodeFilter() {
    ValidateCodeFilter filter = new ValidateCodeFilter();
    filter.setAuthenticationFailureHandler(authenticationFailureHandler());
    return filter;
}

@Bean
public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() {
    SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
    failureHandler.setDefaultFailureUrl("/login?error=true");
    return failureHandler;
}

第五步:添加Thymeleaf模板并测试

最后,我们将创建一个包含登录页面和验证码的Thymeleaf模板。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/login.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <form th:action="@{/login}" th:method="POST" class="form-signin">
        <h2 class="form-signin-heading">Please sign in</h2>
        <input type="text" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" hidden>
        <label for="inputUsername" class="sr-only">Username</label>
        <input type="text" name="username" id="inputUsername" class="form-control" placeholder="Username" required autofocus>
        <label for="inputPassword" class="sr-only">Password</label>
        <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
        <img th:src="@{/captcha}" title="点击刷新" onclick="this.src='/captcha?'+Math.random();"/>
        <input type="text" name="captcha" class="form-control" placeholder="验证码" required>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    </form>
</div>
</body>
</html>

我们可以在配置文件中添加以下内容,将静态资源文件夹设置为“/static”:

spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/

现在,我们可以启动应用程序并通过URL http://localhost:8080/login 打开登录页面。

示例代码

为了更好地理解完整的攻略过程,下面给出两个示例代码,一个是验证码生成器,一个是动态数据源过滤器:

验证码生成器

@Bean
public Producer captcha() {
    Properties properties = new Properties();
    properties.setProperty("kaptcha.border", "yes");
    properties.setProperty("kaptcha.border.color", "105,179,90");
    properties.setProperty("kaptcha.textproducer.font.color", "blue");
    properties.setProperty("kaptcha.image.width", "125");
    properties.setProperty("kaptcha.image.height", "45");
    properties.setProperty("kaptcha.textproducer.font.size", "45");
    properties.setProperty("kaptcha.session.key", "code");
    properties.setProperty("kaptcha.textproducer.char.length", "4");
    properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
    Config config = new Config(properties);
    DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
    defaultKaptcha.setConfig(config);
    return defaultKaptcha;
}

动态数据源过滤器

public class DynamicDataSourceFilter extends AbstractSecurityInterceptor implements Filter {
    private final DynamicDataSourceContextHolder dynamicDataSourceContextHolder;
    private DataSource dataSource1;
    private DataSource dataSource2;

    public DynamicDataSourceFilter(DataSource dataSource1, DataSource dataSource2) {
        this.dataSource1 = dataSource1;
        this.dataSource2 = dataSource2;
        dynamicDataSourceContextHolder = new DynamicDataSourceContextHolder();
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        ServletContext context = request.getSession().getServletContext();
        AuthorizationContext authorizationContext = (AuthorizationContext) context.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        if (authorizationContext == null) {
            filterChain.doFilter(request, response);
            return;
        }
        if (request.getRequestURI().startsWith("/admin")) {
            dynamicDataSourceContextHolder.setDataSourceName("dataSource2");
        } else {
            dynamicDataSourceContextHolder.setDataSourceName("dataSource1");
        }
        filterChain.doFilter(request, response);
        dynamicDataSourceContextHolder.clearDataSourceName();
    }

    @Override
    public void destroy() {

    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        FilterInvocation filterInvocation = (FilterInvocation) fi;
        InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
        try {
            filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }
}

希望这个攻略对你有所帮助!

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security配置多个数据源并添加登录验证码的实例代码 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • JavaWeb简单用户登录注册实例代码(有验证码)

    下面来详细讲解“JavaWeb简单用户登录注册实例代码(有验证码)”的完整攻略。 1. 需求分析 在开始编写代码前,首先需要明确需求。这个JavaWeb实例主要实现以下功能: 用户注册:包括用户名、密码、确认密码以及验证码; 用户登录:包括用户名、密码以及验证码的校验; 验证码:生成随机数,用户填写后验证; 2. 技术栈 这个JavaWeb实例的技术栈主要包…

    Java 2023年6月15日
    00
  • Spring Security认证机制源码层探究

    Spring Security认证机制源码层探究 Spring Security是一个基于Spring框架的安全认证授权框架,它提供了一套完善的安全认证授权解决方案,提供了一系列的安全机制,例如用户名和密码认证、记住我、自动登录、动态权限控制、强制访问控制、会话管理等。 Spring Security认证机制基本原理 Spring Security的认证机制…

    Java 2023年5月20日
    00
  • Spring Boot 异步框架的使用详解

    SpringBoot异步框架的使用详解 Spring Boot提供了异步执行任务的能力。这样的好处是可以让Tomcat等容器可以释放当前线程,从而不会阻塞其他的请求,并且优化服务器资源,从而提供更好的性能。 异步框架概述 Spring Boot中异步框架主要包括异步调用和异步任务两方面。 异步调用 直接从控制器中异步执行一个函数。当这个异步函数执行完成之后,…

    Java 2023年5月15日
    00
  • Spring MVC 自定义数据转换器的思路案例详解

    Spring MVC 自定义数据转换器的思路案例详解 Spring MVC 是一个非常流行的 Java Web 框架,它提供了很多便捷的功能,其中包括数据转换器。数据转换器可以将请求参数转换为 Java 对象,或将 Java 对象转换为响应参数。Spring MVC 默认提供了很多数据转换器,但有时候我们需要自定义数据转换器来满足特定的需求。本文将详细讲解 …

    Java 2023年5月18日
    00
  • java复制文件和java移动文件的示例分享

    下面是Java复制文件和移动文件的示例攻略: 复制文件 1. 使用Java NIO库 Java NIO库提供了Channel和ByteBuffer两个类来进行文件复制操作。以下是一个简单的示例: import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.B…

    Java 2023年5月20日
    00
  • mybatis深入讲解resultMap的定义及用法

    MyBatis深入讲解resultMap的定义及用法 在使用MyBatis进行数据操作时,查询结果可能会被映射到Java对象中或者直接返回Map类型数据,而MyBatis提供了resultMap来帮助我们自定义查询结果的映射方式。本文将详细介绍resultMap的定义及用法。 ResultMap定义 resultMap是一个非常重要的MyBatis配置元素,…

    Java 2023年5月20日
    00
  • 为什么Java 8取消了永久代?

    为什么Java 8取消了永久代? 在Java 8之前,Java虚拟机有一块非堆内存称为永久代(PermGen),它专门用于存放类的元数据信息、常量池、方法区和静态变量等内容。由于永久代有一定的内存限制,并且它是基于线性扫描和GC Roots扫描来进行垃圾回收的,所以在大量类的场景下容易出现“永久代溢出”的问题。此外,永久代和堆内存的内存管理方式不同,会导致被…

    Java 2023年5月11日
    00
  • EL表达式简介_动力节点Java学院整理

    EL表达式简介 什么是EL表达式 EL表达式是JSP2.0引入的一个表达式语言,它可以在JSP页面中快速地访问JavaBean、request请求、session会话和application上下文中的数据。 EL表达式语法 EL表达式以${}封装,其中${}中的内容就是表达式。通过.来访问JavaBean中的属性,通过[]访问Map中的值。 访问JavaBe…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部