SpringSecurity Web 权限方案

1 设置登录的用户名和密码

1.1 通过配置文件

  • application.properties
server.port=8181

# 设置登录的用户名和密码
spring.security.user.name=admin
spring.security.user.password=123456

1.2 通过配置类

  • SpringSecurityConfig.java
package com.sunxiaping.springsecurity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123456");
        auth.inMemoryAuthentication().withUser("admin").password(password).roles("ADMIN");
    }
}

1.3 自定义编写UserDetailsService实现类

  • UserDetailsServiceImpl.java
package com.sunxiaping.springsecurity.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (!"admin".equals(username)) {
            throw new UsernameNotFoundException("用户不存在");
        }
        String password = passwordEncoder.encode("123456");
        Collection<? extends GrantedAuthority> authorities = Stream.of(new SimpleGrantedAuthority("ADMIN")).collect(Collectors.toList());
        UserDetails userDetails = new User(username, password, authorities);
        return userDetails;
    }
}
  • SpringSecurityConfig.java
package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.naming.Name;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

2 查询数据库完成认证

2.1 导入JPA等相关jar包的Maven坐标

  • 修改部分:
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
  • 完整部分:
<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.sunxiaping</groupId>
    <artifactId>spring-security</artifactId>
    <version>1.0</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2 sql脚本

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

insert into (id,username,password) users values(1,'admin','$2a$10$Ug6eGqhTX7wY8ZVIe2PbC.ljVWEko5h7ZH92N.rg0ZjZBcgg2VOqm');

2.3 修改配置文件

  • application.properties
server.port=8181
# 数据库连接配置信息
spring.datasource.url=jdbc:mysql://192.168.1.57:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
# JPA相关配置
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=true

2.4 编写实体类

  • Users.java
package com.sunxiaping.springsecurity.domain;

import lombok.*;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 14:37
 */
@Table(name = "users")
@Entity
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Users implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;
}

2.5 编写UsersRepository接口

package com.sunxiaping.springsecurity.dao;

import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 14:43
 */
public interface UsersRepository extends JpaRepository<Users, Long>, JpaSpecificationExecutor<Users> {

}

2.6 编写UserDetailsService的实现类

package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ADMIN");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

2.7 编写SpringSecurity的配置类

package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

2.8 启动类

package com.sunxiaping.springsecurity;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableJpaAuditing
@EnableTransactionManagement
public class SpringSecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }

}

3 未认证请求跳转到登录页面

3.1 导入thymeleaf相关jar包的Maven坐标

  • 修改部分:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • 完整部分:
<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.sunxiaping</groupId>
    <artifactId>spring-security</artifactId>
    <version>1.0</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.2 编写WebMvcConfig

package com.sunxiaping.springsecurity.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 16:07
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login.html").setViewName("login");
        registry.addViewController("/").setViewName("login");
//        registry.addViewController("/login").setViewName("login");
//        registry.addViewController("/index").setViewName("login");
        registry.addViewController("/success").setViewName("success");
        registry.addViewController("/failure").setViewName("failure");
    }
}

3.3 在templates目录下新建login.html、success.html和failure.html

在templates目录下新建login.html、success.html和failure.html

  • login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>

<form th:action="@{/login}" method="post">
    用户名: <input type="text" name="username"><br>
    密码:<input type="password" name="password"> <br>
    <input type="submit" value="登录">
</form>

</body>
</html>
  • success.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    登录成功
</body>
</html>
  • failure.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    登录失败
</body>
</html>

3.4 修改SpringSecurityConfig

package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello")
                .permitAll()
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}

4 基于角色或权限进行访问控制

4.1 hasAuthority()方法

  • 如果当前的主体具有指定的权限,则返回true,否则返回false。

  • 修改SpringSecurityConfig.java

package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                //-----------设置权限admins------------
                .antMatchers("/test/hello").hasAuthority("admins")
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}
  • 修改UserDetailsServiceImpl.java
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        //这边的admins要和SpringSecurityConfig中.antMatchers("/test/hello").hasAuthority("admins")中的admins一致
        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admins");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

4.2 hasAnyAuthority方法

  • 如果当前的主体具有很多指定的权限的话,返回true。

  • 修改SpringSecurityConfig.java

package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                //-----------设置权限admins,hellos------------
                .antMatchers("/test/hello").hasAnyAuthority("admins", "hellos")
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}
  • 修改UserDetailsServiceImpl.java
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        //这边的admin和hellos要和SpringSecurityConfig中.antMatchers("/test/hello").hasAnyAuthority("admins", "hellos")中的admins和hellos一致
        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,hellos");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

4.3 hasRole方法

  • 如果用户具备给定角色就允许访问,否则出现403。

  • 修改SpringSecurityConfig.java

package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                //-----------设置角色为ADMIN,那么数据库中对应的角色必须为ROLE_ADMIN------------
                .antMatchers("/test/hello").hasRole("ADMIN")
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}
  • 修改UserDetailsServiceImpl.java
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

4.4 hasAnyRole方法

  • 表示用户具备任何一个角色都可以访问。

  • 修改SpringSecurityConfig.java

package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                //-----------设置角色为ADMIN,那么数据库中对应的角色必须为ROLE_ADMIN------------
                .antMatchers("/test/hello").hasAnyRole("ADMIN", "TEST")
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}
  • 修改UserDetailsServiceImpl.java
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN,ROLE_TEST");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

5 自定义403页面

  • 修改访问配置类:
package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //自定义403页面
        http.exceptionHandling().accessDeniedPage("/403");

        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                //-----------设置角色为ADMIN,那么数据库中对应的角色必须为ROLE_ADMIN------------
                .antMatchers("/test/hello").hasAnyRole("ADMIN", "TEST")
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}
  • 在templates目录下新建error目录,并新建4xx.html文件:

在templates目录下新建error目录,并新建4xx.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>403</title>
</head>
<body>
    对不起,你没有权限访问。
</body>
</html>

6 使用注解进行用户授权

6.1 前提

  • 在启动类或配置类中开启全局方法级别的安全控制:
package com.sunxiaping.springsecurity;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableJpaAuditing
@EnableTransactionManagement
//开启全局方法级别的安全控制
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SpringSecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }

}

6.2 @Secured注解

  • 此注解用于判断是否具有某个角色,需要注意的是,匹配的字符串前面需要添加“ROLE_”。

  • 示例:

package com.sunxiaping.springsecurity.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 16:16
 */
@RestController
public class TestController {

    @Secured({"ROLE_SALE","ROLE_ADMIN"})
    @GetMapping(value = "/test/hello")
    public String hello(){
        return "test/hello";
    }

}
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        //AuthorityUtils的commaSeparatedStringToAuthorityList方法的入参需要和@Secured中的一致,否则会报错,当然实际项目中是从数据库中查询得到的
        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_SALE,ROLE_ADMIN");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

6.2 @PreAuthorize注解

  • @PreAuthorize注解适合进入方法前的权限验证。

  • 示例:

package com.sunxiaping.springsecurity.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 16:16
 */
@RestController
public class TestController {

    @PreAuthorize("hasAnyAuthority('sys:test','sys:add')")
    @GetMapping(value = "/test/hello")
    public String hello(){
        return "test/hello";
    }

}
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        //AuthorityUtils的commaSeparatedStringToAuthorityList方法的入参需要和@PreAuthorize中的一致,否则会报错,当然实际项目中是从数据库中查询得到的
        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("sys:test,sys:add");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

6.3 @PostAuthorize注解

  • @PostAuthorize注解使用的不多,在方法执行后再进行权限校验,适合验证带有返回值的权限。

  • 示例:

package com.sunxiaping.springsecurity.controller;

import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 16:16
 */
@RestController
public class TestController {

    @PostAuthorize("hasAnyAuthority('sys:test','sys:add')")
    @GetMapping(value = "/test/hello")
    public String hello(){
        return "test/hello";
    }

}
package com.sunxiaping.springsecurity.service;

import com.sunxiaping.springsecurity.dao.UsersRepository;
import com.sunxiaping.springsecurity.domain.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:57
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Optional<Users> optional = usersRepository.findOne(Example.of(Users.builder().username(username).build()));

        Users users = optional.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        //AuthorityUtils的commaSeparatedStringToAuthorityList方法的入参需要和@PostAuthorize中的一致,否则会报错,当然实际项目中是从数据库中查询得到的
        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("sys:test,sys:add");

        UserDetails userDetails = new User(username, users.getPassword(), authorities);
        return userDetails;
    }
}

7 用户注销

7.1 在配置类中添加退出的映射地址

  • SpringSecurityConfig的修改部分:
//添加退出的映射地址
http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();
  • SpringSecurityConfig的完整部分:
package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置没有权限访问跳转自定义页面
        http.exceptionHandling().accessDeniedPage("/403.html");

        //添加退出的映射地址
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();

        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}

8 自动登录

8.1 自动登录原理

自动登录原理

8.2 自动登录

  • 创建配置类,向容器中注入PersistentTokenRepository组件。
package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private DataSource dataSource;

    /**
     * 向容器中注入PersistentTokenRepository组件
     *
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动创建表,第一次执行会创建,以后执行需要注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }


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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置没有权限访问跳转自定义页面
        http.exceptionHandling().accessDeniedPage("/403.html");

        //添加退出的映射地址
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();

        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF
    }
}
  • 在配置类中,开启记住我功能。
package com.sunxiaping.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * SpringSecurity的配置类
 *
 * @author 许大仙
 * @version 1.0
 * @since 2020-10-28 13:38
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private DataSource dataSource;

    /**
     * 向容器中注入PersistentTokenRepository组件
     *
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动创建表,第一次执行会创建,以后执行需要注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }


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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置没有权限访问跳转自定义页面
        http.exceptionHandling().accessDeniedPage("/403.html");

        //添加退出的映射地址
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();

        http.formLogin() //自定义自己编写的登录页面
                .loginPage("/login.html") //登录页面设置
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")//登录访问的路径
                .defaultSuccessUrl("/success") //登录成功,跳转的路径
                .failureUrl("/failure")
                .permitAll() //指定路径,无需保护
                .and()
                .authorizeRequests()
                .antMatchers("/", "/login", "/test/hello").permitAll()
                .anyRequest() //其他路径,需要认证
                .authenticated()
                .and().csrf().disable();//关闭CSRF

        //开启记住我功能,并设置记住我为一周
        http.rememberMe().tokenRepository(persistentTokenRepository()).userDetailsService(userDetailsService).tokenValiditySeconds(7 * 24 * 60 * 60);
    }
}
  • 在页面添加记住我复选框:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>

<form th:action="@{/login}" method="post">
    用户名: <input type="text" name="username"><br>
    密码:<input type="password" name="password"> <br>
    记住我:<input type="checkbox" name="remember-me" id="">
    <input type="submit" value="登录">
</form>

</body>
</html>
原文地址:https://www.cnblogs.com/xuweiweiwoaini/p/13897385.html