Spring Secutity

Spring Security是一款基于Spring的安全框架,Spring Security是一个为系统提供声明式的安全访问控制的轻量级框架。它为应用程序提供身份验证,授权和针对常见攻击的保护。

Spring Security中文文档
https://www.springcloud.cc/spring-security.html#overall-architecture

概述

SpringSecurity 是基于Spring AOP和Servlet过滤器的安全框架。它提供全面的安全性解决方案,在 Web 请求级和方法调用级处理用户认证(Authentication)和用户授权(Authorization)。他提供了强大的企业安全服务,如:认证授权机制、Web资源访问控制、业务方法调用访问控制、领域对象访问控制Access Control List(ACL)、单点登录(SSO)等等。

Spring Security在架构上将认证与授权分离,并提供了扩展点。它是一个轻量级的安全框架,它确保基于Spring的应用程序提供身份验证和授权支持。它与Spring MVC有很好的集成 ,并配备了流行的安全算法实现捆绑在一起。

核心功能:认证(你是谁)、授权(你能干什么)、攻击防护(防止伪造身份)。

用户认证与授权

Spring Security 基于 Spring 框架,一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。

用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。

用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

解决安全性问题

Spring Security主要是从两个方面解决安全性问题:
Web请求级别:使用Servlet过滤器保护Web请求并限制URL级别的访问
方法调用级别:使用Spring AOP保护方法调用,确保具有适当权限的用户采用访问安全保护的方法.

基本原理

SpringSecurity的核心是一个过滤器链,所有的请求都会经过这些过滤器,通过拦截url从而实现权限的控制。每个过滤器都有特定的职责,可通过配置添加、删除过滤器。过滤器的排序很重要,因为它们之间有依赖关系。有些过滤器也不能删除,如处在过滤器链最后几环的ExceptionTranslationFilter(处理后者抛出的异常),FilterSecurityInterceptor(最后一环,根据配置决定请求能不能访问服务)。

比较重要的三条过滤器:

  1. FilterSecurityInterceptor:是一个方法级的权限过滤器,基本位于过滤器链的最底部。
  2. ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常。
  3. UsernamePasswordAuthenticationFilter:对/login的post请求做拦截,校验表单中的用户名和密码。

过滤器加载流程

使用SpringSecurity配置过滤器(DelegatingFilterProxy),在doFilter方法里使用初始化方法,得到一个叫FilterChainProxy的过滤器,在FilterChainProxy过滤器中得到所有的过滤器并加载到过滤链中,在SecurityFilterChain过滤器中调用getFilters方法完成加载。

实现Security需要用到两个比较重要的接口:
1、UserDetailsService接口:什么都没有配置的时候,登录账号和密码是由Sercurity定义生成,但当我们需要实际的账号和密码时,就需要通过自定义逻辑控制认证逻辑。
2、PasswordEncoder接口:数据加密接口,其中BCryptPasswordEncoder是Security官方推荐的密码解析器。表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配,如果密码匹配则返回 true。
.
.
.
.
.
.
.

使用 Spring Security

创建SpringBoot项目(SpringBoot2.1.5),引入依赖并启动服务,自动开启Spring Security的功能。

在不做任何配置的情况下,Security会把服务内所有资源的访问都保护起来,需要先进行身份证认证才可访问, 使用默认的表单登录或http basic认证方式。

引入依赖

在maven的pom.xml中引入依赖。一般不需要指定版本号,Security的版本会跟随SpringBoot的版本。

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

启动服务

访问默认的服务地址,就能看到Spring Security默认的登录页面,默认的登录名是user,密码在输出在控制台上面。
SpringSecurity默认登录页面在DefaultLoginPageGeneratingFilter类里面的generateLoginPageHtml产生的。
在这里插入图片描述

设定用户名和密码

在application.properties中做如下设定,使用用户名admin密码123访问系统。
spring.security.user.name=admin
spring.security.user.password=123

自定义登录页

创建自定义的Java配置类WebSecurityConfig.java,继承WebSecurityConfigureAdapter抽象类,使用@Configuration和 @EnableWebSecurity进行注解声明配置。实现configure(HttpSecurity http)方法,设置一些跟网页请求相关的设置。

在设置参数的时候可以使用链式编程,在后面添加 . 就能不断的进行配置,我们用http下面的formLogin下面的方法来设置我们的登录页。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable(); //关闭csrf,默认是开启的,开启后会导致我们的登录被拦截,导致登录失败
        http.formLogin()
                .loginPage("/toLogin") //设置默认登录页
                .usernameParameter("username") //设置从前端提交过来的用户名参数
                .passwordParameter("password") //设置从前端提交过来的密码参数
                .defaultSuccessUrl("/index") //设置默认登录页面,会跳转到登录前的路径
//                .successForwardUrl("/index") //登录成功后页面,无论前面为什么请求,都会跳转到这个路径
                .failureForwardUrl("/toLogin") //设置登录失败后的请求
                .loginProcessingUrl("/login"); //设置登录请求路径
    }
}

配置解析

@EnableWebSecurity 查看其注解源码,主要是引用WebSecurityConfiguration.class 和 加入了@EnableGlobalAuthentication 注解,这里只要明白添加 @EnableWebSecurity 注解将开启 Security 功能。
1. formLogin() 使用表单登录(默认请求地址为 /login),在SpringSecurity5 里其实已经将旧版本默认的 httpBasic() 更换成 formLogin()了,这里为了表明表单登录还是配置了一次。
2. authorizeRequests() 开始请求权限配置
3. antMatchers() 使用Ant风格的路径匹配,这里配置匹配 //index
4. permitAll() 用户可任意访问
5. anyRequest() 匹配所有路径
6. authenticated() 用户登录后可访问

用户授权

在网页中有些特定的页面只能有对应的权限才能访问。
启动项目可以访问index.html,所有人都可以访问,但是admin和user的测试页面在没有登录的情况下无法访问,会直接跳转到登录页面。
在之前的自定义登录页面前加入如下代码

//antMatchers括号里面可以输入多个请求路径,用逗号隔开
http.authorizeRequests() //设置访问请求的权限
        .antMatchers("/") //默认首页允许所有用户都可以访问,不登录也能访问
            .permitAll()
        .antMatchers("/admin/*") //admin下面的页面只有拥有admin角色的用户才能访问
            .hasRole("admin")
        .antMatchers("/user/*") //user下面的页面只有拥有user角色的用户才能访问
            .hasRole("user");

4. 用户认证

用户认证是用户在登录的时候验证用户的用户名和密码并赋予他们相应的权限,从数据库中查看全部用户的信息,然后将所有的用户信息进行认证,然后登录用户就能获得相应的权限去访问相应的页面。

InMemoryUserDetailsManager:顾名思义,将用户名密码存储在内存中的用户管理器,可设定多个用户。
如果正常开发需要连接数据库,通过数据库查找到用户的信息进行认证并赋予权限。

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //使用BCryptPasswordEncoder对密码进行加密
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("admin") //给admin用户添加admin权限
                .password(new BCryptPasswordEncoder().encode("123456")).roles("admin","user")
            .and()
            .withUser("user") //给user用户添加user权限
                .password(new BCryptPasswordEncoder().encode("123456")).roles("user");
登录user

user访问admin接口,返回403提示无权限
在这里插入图片描述

放行静态资源

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/css/**");
}
记住我

5. 注销
//注销用户,注销成功后跳转到/请求
http.logout().logoutSuccessUrl("/");


.
.
.
.
.
.

SpringBoot 整合Spring Security(一) 自定义用户名密码认证

表单输入用户名密码,结合数据库方式进行身份认证和权限鉴定。通过这样一个过程来熟悉 Spring Security 的认证流程,掌握 Spring Security 的原理。

Spring Security 执行登录认证过程
在这里插入图片描述

自定义配置类

创建一个自定义的Java配置类SpringSecurityConfig,继承WebSecurityConfigurerAdapter抽象类。使用@Configuration和 @EnableWebSecurity进行注解声明配置。

该配置类继承抽象类 WebSecurityConfigurerAdapter,重写内部的方法就可以了,分别是对AuthenticationManagerBuilder,WebSecurity,HttpSecurity方法,最终实现自定义认证。

配置资源认证规则

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    @Autowired
    private UserDetailsService userDetailsService;

    /**
    * 配置用户认证, 使用自定义身份验证组件
    */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // auth.userDetailsService(userDetailsService);
        
        //创建DaoAuthenticationProvider
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        //设置userDetailsService,基于数据库方式进行身份认证
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder()); //配置密码编码器
        auth.authenticationProvider(provider);
    }

    public void configure(HttpSecurity http)throws Exception{
        http.formLogin(); //输入表单用户名密码

        http.rememberMe().and()
                .cors().and().csrf().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                //.antMatchers("/").permitAll()
                .antMatchers("/admin/**")..hasRole("admin")
                //.antMatchers("/user/**")..hasRole("user")
                .anyRequest().authenticated();// 其他所有请求需要身份认证
    }}

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

实现 UserDetailsService

UserDetailsService是Spring Security中的一个接口,它用于从特定数据源(如数据库)中获取用户详细信息,以进行身份验证和授权。实现该接口的类需要实现loadUserByUsername()方法,该方法根据给定的用户名返回一个UserDetails对象,该对象包含有关用户的详细信息,例如密码、角色和权限等。在Spring Security中,UserDetailsService通常与DaoAuthenticationProvider一起使用,后者是一个身份验证提供程序,用于验证用户的凭据。

想要关闭UserDetailsService的自动配置,则添加一个自定义实现类UserDetailsServiceImpl,改变认证的用户信息来源,实现 UserDetailsService,重写loadUserByUsername()方法。

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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;


@Service
public class UserDetailsServiceImpl implements UserDetailsService {
	@Autowired
	private LoginDao loginDao;
	@Autowired
	private PermissionDao permissionDao;
	
	//@PostConstruct
    public void initData(){
        String password = passwordEncoder.encode("123456");
        userList.add(new User("admin", password, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin","ROLE_user")));
        userList.add(new User("user", password, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_user")));
    }
    
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User user = loginDao.loadUserByUsername(username);
		if(user == null) {
            throw new UsernameNotFoundException("用户名不存在!" + username);
        }
		user.setPermissions(permissionDao.findPermissionsByUserId(user.id));
		System.out.println("权限列表:" + user.getPermissions());
        return user;
	}}
Controller 测试类
@RestController
public class UserController{

    @GetMapping("/user/getCurrentUser")
    public Object getCurrentUser(Authentication authentication){
        log.info("/user/getCurrentUser ok");
        return "user01 -----" +  authentication;
    }

    //测试类
	@RequestMapping(value = "/test")
	public String test() throws Exception
	{
		return "security test success";
	}
}

访问测试类

访问http://localhost:8080/test,由于我们开启了SpringSecurity且当前是未登录状态,页面会被302重定向到http://localhost:8080/login登录页面。

用户名:user,密码在控制台输出中:d2ee3df0-1924-440a-9b8e-7f3449ee798f

输入正确的用户名密码点击登录,系统重新302到http://localhost:8080/test并显示返回的数据。即:这表示我们的接口已经被spring保护了。

测试接口

输入admin 123456访问接口 http://localhost:9507/user/getCurrentUser

请求结果

UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=admin, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[admin]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=974646B19094BBB5A624D56061E7D507], Granted Authorities=[admin]]


.
.
.
.
.
.

用户登录验证流程

Spring Security原理分析【2】——SecurityFilterChain的构建
https://www.cnblogs.com/xfeiyun/p/16214205.html

springSecurity安全框架的学习和原理解读
https://blog.csdn.net/liushangzaibeijing/article/details/81220610

Spring Security Filter Chain

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1. AbstractAuthenticationProcessingFilter 过滤器

AbstractAuthenticationProcessingFilter 过滤器是一个模版,主要是用来识别是否是认证请求,然后将不是认证请求到给到下一个过滤器的实现类(就是一组过滤器的串联)。这个过滤器中主要是doFilter方法,这个方法中requiresAuthentication 识别是否是认证请求,如果是,那么交给 attemptAuthentication 这个方法去处理,但是attemptAuthentication方法是抽象方法,需要子类去实现,即UsernamePasswordAuthenticationFilter 过滤器,也就是attemptAuthentication方法的具体实现类。

2. UsernamePasswordAuthenticationFilter 过滤器

它实际上是处理 认证请求的过滤器,AbstractAuthenticationProcessingFilter的子类,真正实现类attemptAuthentication方法。

attemptAuthentication方法中,除了进行对请求中用户名、密码参数的处理外,核心的一行是this.getAuthenticationManager().authenticate(authRequest); 这个就是用选择合适的验证类来进行验证,从名称我们也能看出AuthenticationManager 是一个管理类,这个里面有多个AuthenticationProvider 对象。选择合适的验证就行。
但是这个getAuthenticationManager是一个接口,需要找到真正的实现类才行。

3. ProviderManager 管理类

这个类就是真正选择具体的认证类,authenticate方法遍历认证类,然后将请求中的用户名、密码进行验证的。
从上图可以看到,它就是对所有的认证类遍历,选择合适的进行。
provider.authenticate(authentication); 就是它的方法的核心代码。
但是AuthenticationProvider 也是一个接口,需要找其真正的实现类。

然后找到之后,在去调用additionalAuthenticationChecks 方法去验证持久化中的(内存或者retrieveUser方法找到的用户名和密码)是否和请求中的用户名密码一致,如果是一致的,那么就调用additionalAuthenticationChecks 方法去验证。

但是retrieveUser 和 additionalAuthenticationChecks 方法都是抽象方法,具体的实现,是子类进行的。

5. DaoAuthenticationProvider(子类)

这个是AbstractUserDetailsAuthenticationProvider 的子类,实现了retrieveUser 和 additionalAuthenticationChecks 方法,我们可以看到两个方法。

注意看 this.getUserDetailsService().loadUserByUsername(username); 这个方法就是我们自定义获取真正的(也就是持久化中)用户名 和 密码 时需要重写的方法,返回的user 类,就是UserDetails 的子类。

而且,additionalAuthenticationChecks 这个方法,就是调用PasswordEncoder 类中的matches 方法去对比的

至此,我们就将 SpringSecurity 用户登录验证流程走通了。


.
.
.
.
.
.

原理解析 ——认证与授权

Spring Security 原理解析【3】——认证与授权
https://www.cnblogs.com/xfeiyun/p/16214661.html

在这里插入图片描述

官网定义的关键过滤器顺序

在这里插入图片描述

其他说明

@EnableWebSecurity注解

@EnableWebSecurity注解有两个作用,1: 加载了WebSecurityConfiguration配置类, 配置安全认证策略。2: 加载了AuthenticationConfiguration, 配置了认证信息。

WebSecurityConfiguration

WebSecurityConfiguration
其中注入了springSecurityFilterChain这个Bean,这是Spring Secuity的核心过滤器, 这是请求的认证入口。
@EnableGlobalAuthentication
其中注入了AuthenticationConfiguration配置类,这个类的主要作用是,向Spring容器中注入AuthenticationManagerBuilder, AuthenticationManagerBuilder其实是使用了建造者模式, 他能建造AuthenticationManager, 是身份认证的入口。
@EnableWebSecurity注解有两个作用,1: 加载了WebSecurityConfig.java配置类, 配置安全认证策略。2: 加载了AuthenticationConfiguration, 配置了认证信息。

WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter是由Spring Security提供的Web应用安全配置的适配器。

WebSecurityConfiguration注入了SpringSecurityFilterChain这个Bean,这是Spring Secuity的核心过滤器, 这是请求的认证入口。
@EnableGlobalAuthentication
其中注入了AuthenticationConfiguration配置类,这个类的主要作用是,向spring容器中注入AuthenticationManagerBuilder, AuthenticationManagerBuilder其实是使用了建造者模式, 他能建造AuthenticationManager, 是身份认证的入口。
EnableWebSecurity注解有两个作用,1: 加载了WebSecurityConfiguration配置类, 配置安全认证策略。2: 加载了AuthenticationConfiguration, 配置了认证信息。

当Spring项目中引入了Spring Security依赖的时候,项目会默认开启如下配置

UsernamePasswordAuthenticationFilter过滤器用于处理基于表单方式的登录认证。
而BasicAuthenticationFilter用于处理基于HTTP Basic方式的登录验证,后面还可能包含一系列别的过滤器(可以通过相应配置开启)。
在过滤器链的末尾是一个名为FilterSecurityInterceptor的拦截器,用于判断当前请求身份认证是否成功,是否有相应的权限,当身份认证失败或者权限不足的时候便会抛出相应的异常。
ExceptionTranslateFilter捕获并处理,所以我们在ExceptionTranslateFilter过滤器用于处理了FilterSecurityInterceptor抛出的异常并进行处理,比如需要身份认证时将请求重定向到相应的认证页面,当认证失败或者权限不足时返回相应的提示信息。

@EnableGlobalMethodSecurity注解详解

当开启spring方法级安全时,只需要在任何 @Configuration实例上使用 @EnableGlobalMethodSecurity 注解就能达到此目的。这个注解为我们提供了prePostEnabled 、securedEnabled 和 jsr250Enabled 三种不同的机制来实现同一种功能

prePostEnabled = true 会解锁 @PreAuthorize 和 @PostAuthorize 两个注解。从名字就可以看出@PreAuthorize 注解会在方法执行前进行验证,而 @PostAuthorize 注解会在方法执行后进行验证。
原文链接:https://blog.csdn.net/chihaihai/article/details/104678864

UserDetailsService 和 AuthenticationProvider

UserDetailsService 和 AuthenticationProvider 这两个接口在Spring Security中扮演着至关重要的角色,通过它们可以实现自定义的用户认证逻辑和身份验证过程。

认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。

DaoAuthenticationProvider

DaoAuthenticationProvider 便是用于解析并认证 UsernamePasswordAuthenticationToken 的这样一个认证服务提供者。

DaoAuthenticationProvider解析
https://www.clzg.cn/article/332481.html

BCryptPasswordEncoder密码编码器

BCryptPasswordEncoder是Spring Security中一种基于bcrypt算法的密码加密方式。bcrypt算法是一种密码哈希函数,具有防止彩虹表攻击的优点,因此安全性较高。

使用BCryptPasswordEncoder进行密码加密时,可以指定一个随机生成的salt值,将其与原始密码一起进行哈希计算。salt值可以增加密码的安全性,因为即使两个用户使用相同的密码,由于使用不同的salt值进行哈希计算,得到的哈希值也是不同的。

HttpSecurity常用参数

HttpSecurity常用参数,如下图用法基本脱离不了下面这些方法,可以基于认证的方式有formLogin、openidLogin、oauth2Login,还可以做一些记住账号操作rememberMe,还可以进行session配置管理,还支持登出loginout等。

在这里插入图片描述
.
.
.

参考资料

Spring Security中文文档
https://www.springcloud.cc/spring-security.html#overall-architecture

Spring Boot2.0使用Spring Security
https://www.cnblogs.com/wtzbk/p/9387859.html

使用SpringBoot整合SpringSecurity
https://blog.csdn.net/qq_59570311/article/details/123157577

基于SpringBoot搭建应用开发框架(二) —— 登录认证
https://www.cnblogs.com/chiangchou/p/springboot-2.html#_label2_2

Spring Security 原理解析【3】——认证与授权
https://www.cnblogs.com/xfeiyun/p/16214661.html

SpringSecurity的认证流程分析(各个组件之间的关联)
https://blog.csdn.net/qq_35363507/article/details/121291755

SpringBoot2.x整合Security5(完美解决 There is no PasswordEncoder mapped for the id “null”)
https://blog.csdn.net/SWPU_Lipan/article/details/80586054
https://blog.csdn.net/qq_21963133/article/details/81066714

springSecurity安全框架的学习和原理解读
https://blog.csdn.net/liushangzaibeijing/article/details/81220610

草稿

SimpleUrlAuthenticationSuccessHandler

LoginAuthenticationSuccess.java

@Component
public class LoginAuthenticationSuccess extends SimpleUrlAuthenticationSuccessHandler {
	@Autowired
	private ObjectMapper objectMapper;
	
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException
	{
		System.out.println("---Authentication Success(登录成功): " + authentication); 
		System.out.println("---getPrincipal: " + authentication.getPrincipal());
		response.setContentType("application/json;charset=UTF-8");
		response.getWriter().write(objectMapper.writeValueAsString(authentication));
	}
}

限制最大登录数

config()中添加

.sessionManagement()
	.invalidSessionUrl("/login/invalid")
	.maximumSessions(1)
	// 当达到最大值时,是否保留已经登录的用户
	.maxSessionsPreventsLogin(false)
	// 当达到最大值时,旧用户被踢出后的操作
    .expiredSessionStrategy(new CustomExpiredSessionStrategy())

loginProcessingUrl

如果只配置loginPage而不配置loginProcessingUrl的话
那么loginProcessingUrl默认就是loginPage
你配置的loginPage(“/testpage.html”) ,那么loginProcessingUrl就是"/testpage.html"

优先级从上向下:
.successHandler(authenticationSuccess)
.successHandler(new ForwardAuthenticationSuccessHandler(“/index2”))
.defaultSuccessUrl(“/index1”)

PasswordEncoder 自定义编码器

MyPasswordEncoder.java

public class MyPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }
    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.equals(charSequence.toString());
    }
}

其他
在这里插入图片描述

关闭CSRF跨域

关闭CSRF跨域 CSRF(Cross-site request forgery)跨站请求伪造,也被称为one-click attack单键攻击;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private LoginAuthenticationSuccess authenticationSuccess;//验证成功的处理类
    
	@Bean
	protected UserDetailsService userDetailsService()	{
		return new UserDetailsServiceImpl();
	}
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
    }
	
	@Override
	public void configure(HttpSecurity http) throws Exception	{
		http
			.authorizeRequests() //其他地址的访问均需验证权限
			.anyRequest()
			.authenticated()
			.and()
		.formLogin()
			.loginPage("/login.html")
			.loginProcessingUrl("/loginSub")
			//.defaultSuccessUrl("/")
			.successHandler(authenticationSuccess)
			.failureUrl("/failure.html")
			.permitAll()
			.and()
		.logout()
			.logoutUrl("/logout")
			.permitAll();
		http.csrf().disable();
		//
		//http.sessionManagement().invalidSessionUrl("/session/invalid"); //session失效时间
		//http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); //无权访问处理器
	}

    @Override
    public void configure(WebSecurity web) throws Exception {
    	System.out.println("configure(WebSecurity web)...");
    	//解决静态资源被拦截的问题
    	web.ignoring().antMatchers("/static/**");
        web.ignoring().antMatchers("/css/**");
        web.ignoring().antMatchers("/js/**");
        web.ignoring().antMatchers("/images/**");
        web.ignoring().antMatchers("/**/favicon.ico");
        web.ignoring().antMatchers("/lib/**");
        web.ignoring().antMatchers("/fonts/**");
        web.ignoring().antMatchers("/lang/**");
        web.ignoring().antMatchers("/login.html");
        //解决服务注册url被拦截的问题
        web.ignoring().antMatchers("/**/*.json");
    }
}

SpringSecurity细分:

Web/Http 安全:这是最复杂的部分。通过建立 filter 和相关的 service bean 来实现框架的认证机制。当访问受保护的 URL 时会将用户引入登录界面或者是错误提示界面。
业务对象或者方法的安全:控制方法访问权限的。
AuthenticationManager:处理来自于框架其他部分的认证请求。
AccessDecisionManager:为 Web 或方法的安全提供访问决策。会注册一个默认的,但是我们也可以通过普通 bean 注册的方式使用自定义的 AccessDecisionManager。
AuthenticationProvider:AuthenticationManager 是通过它来认证用户的。
UserDetailsService:跟 AuthenticationProvider 关系密切,用来获取用户信息的。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐