SpringSecurity主要扩展点

主体数据来源:通过自己实现一个UserDetailsService对象并注入到Spring容器 中,来实现自定义的主体数据管理

package com.vn.config;

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;

/**
 * @author VN
 * 致敬未来的你
 * @date 2022/6/25  14:20
 *
 * 主体数据来源
 */
public class MyUserService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        if ("vn".equals(username)){
            return User.withUsername("vn").password("123456").authorities("mobile", "salary").build();
        }
        return null;
    }
}
package com.vn.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.sql.DataSource;

@Configuration
public class MyWebConfig implements WebMvcConfigurer {
    //默认Url根路径跳转到/login,此url为spring security提供
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // spring security提供默认路径
//        registry.addViewController("/").setViewName("redirect:/login");
        // 自定义跳转路径
        registry.addViewController("/").setViewName("redirect:/index.html");
    }

    /**
     * 自行注入一个PasswordEncoder。
     * Security会优先从Spring容器中获取PasswordEncoder.
     * 注入一个不做任何加解密操作的密码处理器用作演示。
     * 一般常用BCryptPasswordEncoder
     *
     * @return
     */
    @Bean
    public PasswordEncoder getPassWordEncoder() {
//        return new BCryptPasswordEncoder(10);
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     * 自行注入一个UserDetailsService
     * 如果没有的话,在UserDetailsServiceAutoConfiguration中会默认注入一个包含user用户的InMemoryUserDetailsManager
     *
     * @return
     */
    @Bean
    public UserDetailsService userDetailsService() {
//        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(User.withUsername("admin").password("admin").authorities("mobile", "salary").build()
//                , User.withUsername("manager").password("manager").authorities("salary").build()
//                , User.withUsername("worker").password("worker").roles("worker").build());
//        return userDetailsManager;
//        return new JdbcUserDetailsManager(DataSource dataSource);
        return new MyUserService();
    }
}

自定义授权及安全拦截策略

自定义登录:
http.loginPage()方法配置登录页,http.loginProcessingUrl()方法定制登录逻辑

 

 //配置安全拦截策略
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //链式配置拦截策略
        http
                .csrf().disable()//关闭csrg跨域检查
                //这里注意matchere是有顺序的。
                .authorizeRequests()
                .antMatchers("/mobile/**").hasAuthority("mobile")
                .antMatchers("/salary/**").hasAuthority("salary")
                .antMatchers("/worker/**").hasAuthority("ROLE_worker")//等价于hasRole("worker")
                .antMatchers("/common/**").permitAll() //common下的请求直接通过
                .antMatchers("/**.html","/js/**","/css/**","/img/**").permitAll()//放行静态资源
                .anyRequest().authenticated() //其他请求需要登录
                .and()//并行条件
                .formLogin()
                .loginPage("/index.html").loginProcessingUrl("/login")//自定义登录页面
                .defaultSuccessUrl("/main.html").failureUrl("/common/loginFailed"); //可从默认的login页面登录,并且登录后跳转到main.html
    }

 

记住我功能

 

登录页面提供了记住我功能,此功能只需要往登录时提交一个remeber-me的参数,值可以是 on 、yes 、1 、 true,就会记住当前登录用户的token到cookie中。http.rememberMe().rememberMeParameter("remeber-me"),
使用这个配置可以定制参数名。而在登出时,会清除记住我功能的cookie。

 

"username":$("#userName").val(),
"password":$("#userPass").val(),
"remeber-me": "on|yes|1|true"    

拦截策略

 

antMachers()方法设置路径匹配,可以用两个星号代表多层路径,一个星号代表一个或多个字符,问号代表一个字符。然后配置对应的安全策略:

permitAll()所有人都可以访问。denyAll()所有人都不能访问。 anonymous()只有未登录的人可以访问,已经登录的无法访问。 hasAuthority、hasRole这些是配置需要有对应的权限或者角色才能访问。 其中,角色就是对应一个ROLE_角色名 这样的一个资源。 另外的两个配置对象中,AuthenticationManagerBuilder配置认证策略,WebSecurity配置补充的Web请求策略

 

关于csrf

 

csrf全称是Cross—Site Request Forgery 跨站点请求伪造。这是一种安全攻击手段,简单来说,就是黑客可以利用存在客户端的信息来伪造成正常客户,进行攻击。例如你访问网站A,登录后,未退出又打开一个tab页访问网站B,这时候网站B
就可以利用保存在浏览器中的sessionId伪造成你的身份访问网站A。
我们在示例中是使用http.csrf().disable()方法简单的关闭了CSRF检查。而其实Spring Security针对CSRF是有一套专门的检查机制的。他的思想就是在后台的session中加入一个csrf的token值,然后向后端发送请求时,对于GET、HEAD、
TRACE、OPTIONS以外的请求,例如POST、PUT、DELETE等,会要求带上这个token值进行比对。
当我们打开csrf的检查,再访问默认的登录页时,可以看到在页面的登录form表单中,是有一个name为csrf的隐藏字段的,这个就是csrf的token。例如我们在freemarker的模板语言中可以使用添加这个参数。
而在查看Spring Security后台,有一个CsrfFilter专门负责对Csrf参数进行检查。他会调用HttpSessionCsrfTokenRepository生成一个CsrfToken,并将值保存到Session中。

 

posted @ 2022-06-25 15:58  VNone  阅读(172)  评论(0)    收藏  举报