详解springSecurity之java配置篇

关于“详解springSecurity之java配置篇”完整攻略,我们来详细说一下。

简介

SpringSecurity是基于Spring框架的安全框架,主要解决的是在应用程序中如何安全地进行身份认证和授权。本篇文档主要讲解如何使用Java配置的方式来进行SpringSecurity的配置。

步骤

1. 添加spring-security配置依赖

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

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.5.1</version>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.5.1</version>
</dependency>

2. 配置SpringSecurity基础信息

  • 实现 SecurityConfigurerAdapter 类来进行基础 SpringSecurity 配置。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/**").authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .and()
            .logout()
                .logoutSuccessUrl("/login?logout")
                .and()
            .csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }
}

这里使用了 HttpSecurity 来定义如何配置应用程序的各个安全性方面,配置了请求的访问权限和请求的登录页,以及自定注销功能和禁用跨域请求伪造。

  • 配置 UserDetailsService 的实现
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if(user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        return new SecurityUser(user);
    }
}

其中,SecurityUser 是实现 SpringSecurity 的 UserDetails 接口的一个类,用于对数据库中存储的用户密码进行加密。

public class SecurityUser extends User implements UserDetails {

    private static final long serialVersionUID = -5032883717944428014L;

    public SecurityUser(User user) {
        if(user != null) {
            this.setUsername(user.getUsername());
            this.setPassword(user.getPassword());
            this.setEnabled(user.getEnabled());
            this.setAccountNonExpired(user.getAccountNonExpired());
            this.setAccountNonLocked(user.getAccountNonLocked());
            this.setCredentialsNonExpired(user.getCredentialsNonExpired());
            this.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRoles()));
        }
    }
}

3. 配置 SpringSecurity SessionHandlingFilter

在配置基础信息的同时,还需要处理 SpringSecurity 的 session 管理,根据情况对 SessionHandlingFilter 进行自定义调整。

3.1. 配置 SessionCreationPolicy

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                ...
    }
}

这里使用 SessionCreationPolicy.STATELESS 来表示不创建 session。

3.2. 自定义 SessionManagementFilter

public class CustomSessionManagementFilter extends SessionManagementFilter {

    public CustomSessionManagementFilter(SessionAuthenticationStrategy sessionAuthenticationStrategy) {
        super(new NullAuthenticatedSessionStrategy(), new HttpSessionSessionStrategy());
        this.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
    }
}

对于 SessionManagementFilter,这里使用了自定义 CustomSessionManagementFilter 来扩展 SessionManagementFilter 的基础功能。

4. 配置SpringSecurity FilterChainProxy

  • 添加WebApplicationInitializer实现类
public class SecurityWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[0];
    }

    @Override
    protected String[] getServletMappings() {
        return new String[0];
    }
}
  • 添加SecurityFilterChain
public class SecurityWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[0];
    }

    @Override
    protected String[] getServletMappings() {
        return new String[0];
    }

    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);

        DelegatingFilterProxy filterProxy = new DelegatingFilterProxy();
        filterProxy.setTargetBeanName("springSecurityFilterChain");

        return new Filter[]{
                encodingFilter, filterProxy
        };
    }
}

示例

这里列出两个简单的例子,可以了解如何在 Spring Boot 中 (举例)实现基于 Java 配置的 Spring Security。

示例1:基本使用

配置 SpringSecurity 基础信息:

@Configuration
@EnableWebSecurity
public class BasicSecSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/console/**").permitAll()
                .antMatchers("/api/**").permitAll()
                .antMatchers(HttpMethod.POST, "/signup").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .logoutSuccessUrl("/")
                .permitAll();

        http.csrf().disable();
        http.headers().frameOptions().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin").password("{noop}password").roles("ADMIN");
    }
}

@Configuration
public class BasicSecWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{BasicSecSecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

示例2:记住我功能

```java
@Configuration
@EnableWebSecurity
public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private DataSource dataSource;

@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication()
        .dataSource(dataSource)
        .usersByUsernameQuery("select username,password,enabled from users where username=?")
        .authoritiesByUsernameQuery("select username, role from user_roles where username=?")
        .passwordEncoder(passwordEncoder());
}

private PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/signup","/about").permitAll()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
        .logout()
            .deleteCookies("JSESSIONID")
            .permitAll()
            .and()
        .rememberMe()
            .key("privatekey")
            .tokenRepository(persistentTokenRepository())
            .tokenValiditySeconds(60*60*24*7)
    ;

    http.csrf().disable();
}

@Bean
public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
    PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices("privatekey", userDetailsService(), persistentTokenRepository());
    return tokenBasedservice;
}

@Bean
public PersistentTokenRepository persistentTokenRepository() {
    JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
    db.setDataSource(dataSource);
    return db;
}

@Override
public UserDetailsService userDetailsService() {
    return new JdbcUserDetailsManager(dataSource);
}

}

@Configuration
public class RememberMeWebAppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(final ServletContext sc) throws ServletException {
    AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
    root.scan("com.journaldev.spring");
    sc.addListener(new ContextLoaderListener(root));

    AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
    dispatcherServlet.scan("com.journaldev.spring");
    ServletRegistration.Dynamic dispatcher = sc.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
    dispatcher.addMapping("/");
    dispatcher.setLoadOnStartup(1);

    FilterRegistration.Dynamic fr = sc.addFilter("encodingFilter", CharacterEncodingFilter.class);
    fr.setInitParameter("encoding", "UTF-8");
    fr.setInitParameter("forceEncoding", "true");
    fr.addMappingForUrlPatterns(null, true, "/*");

    FilterRegistration.Dynamic fr1 = sc.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class);
    fr1.setInitParameter("targetBeanName", "springSecurityFilterChain");
    fr1.addMappingForUrlPatterns(null, true, "/*");
}

}

这里使用了 remember me 功能,用户登录时,可以选择是否让系统记住自己的 credentials,并在下次会话中自动登录。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解springSecurity之java配置篇 - Python技术站

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

相关文章

  • eclipse/intellij idea 远程调试hadoop 2.6.0

    下面是关于“eclipse/intellij idea 远程调试hadoop 2.6.0”的完整攻略: 简介 在分布式系统开发过程中,我们可能需要对运行在远端的Hadoop集群上的代码进行调试。这时,我们就需要进行远程调试。本文将介绍如何使用Eclipse/IntelliJ IDEA进行远程调试Hadoop 2.6.0,以及具体的步骤和示例。 调试前准备 配…

    Java 2023年5月20日
    00
  • 腾讯云Ubuntu14.04安装Tomcat8教程

    腾讯云Ubuntu14.04安装Tomcat8教程 1. 安装OpenJDK 在Ubuntu14.04下使用如下命令安装OpenJDK: sudo apt-get update sudo apt-get install openjdk-7-jdk 2. 下载Tomcat8 官网下载地址:https://tomcat.apache.org/download-8…

    Java 2023年5月19日
    00
  • 如何在Java程序中访问mysql数据库中的数据并进行简单的操作

    让我们来讲解如何在Java程序中访问MySQL数据库中的数据并进行简单的操作。 步骤一:下载并安装MySQL连接器 在开始编写Java程序之前,需要下载并安装MySQL的JDBC驱动程序。可以在MySQL官方网站下载最新版本的MySQL连接器。下载完成后,将.jar文件添加到Java项目的类路径中。 步骤二:创建数据库连接 在Java程序中连接MySQL数据…

    Java 2023年5月19日
    00
  • JAVA获取文件绝对路径的方法

    获取Java文件的绝对路径可助于在程序中读取或写入文件。下面将详细介绍Java中获取文件绝对路径的方法。 1. 通过File类的getAbsolutePath()方法获取文件路径 使用File类的getAbsolutePath()方法获取文件的绝对路径非常简单,只需要将文件对象作为参数传入即可。示例如下: File file = new File(&quot…

    Java 2023年5月20日
    00
  • Java中启动线程start和run的两种方法

    启动线程是Java并发编程中的重要话题。在Java中,启动线程有两种方法,分别是调用Thread类的start()方法和直接调用run()方法。 为什么要使用线程 在Java中,线程的创建和启动可以让程序并发执行,实现多任务的处理。进程是由操作系统进行资源分配和调度的,而线程是在进程的基础上创建的,可以利用CPU时间片轮流获得执行时间。这样就可以让程序在一定…

    Java 2023年5月26日
    00
  • 在Java编程中定义方法

    在Java编程中定义方法,可以方便地对代码进行模块化,同时也可以提高代码的可读性和可维护性。下面,我将详细讲解Java编程中定义方法的完整攻略。 什么是方法? 在Java中,方法(Method)是一个独立的代码块,用于封装一些指令。它可以接受参数,处理数据以及返回值。我们可以在代码中通过调用方法来执行其中的指令。方法可以用于多处调用,提高了代码的复用性。 方…

    Java 2023年5月26日
    00
  • java如何利用poi解析doc和docx中的数据

    当需要从 Word 文档中提取数据的时候,我们可以使用 Apache POI 来读取 “.doc” 和 “.docx” 文件。下面是如何利用 POI 解析 Word 文档中数据的攻略: 1. 添加 POI 依赖 在项目中添加以下依赖: <dependency> <groupId>org.apache.poi</groupId&g…

    Java 2023年5月20日
    00
  • java门禁系统面向对象程序设计

    Java门禁系统面向对象程序设计的攻略如下: 1.系统需求分析 在进行Java门禁系统的设计之前,需要对系统的需求进行分析,包括基本功能、用户需求、系统限制等,从而有针对性地设计程序。 2.系统设计 在完成需求分析后,可以开始设计系统,包括系统架构、类的设计、模块的分配等,充分考虑系统的可扩展性、可维护性等方面,尽量使系统的设计更加合理化。 3.系统实现 实…

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