Spring Security文章梳理

为了提高项目组生产效率和适应市场人才技术线,项目其中一个模块决定摒弃公司传统的Spring+Struts框架(技术老旧,工程体量庞大),采用SpringBoot新搭建一个工程。登录认证、权限管理这些系统基础功能自然少不了。项目还达不到微服务架构的地步,SpringCloudAuth2的方案太重,先只打算用Spring Security。本文章记录一下搜寻的各有关Spring Security的文章,不断的更新中。。。

参考文章

SpringBoot集成Spring Security

【置顶】Spring Security 5

总共10篇文章;
从简单例子到原理

Spring Security原理篇(三) HttpSecurity https://www.jianshu.com/p/6f1b129442a1

1.初始化HttpSecurity对象
1.2.3 HttpSecurity的部分方法 2 从配置到Filter
2.1 formLogin()的原理
2.1.1 formLogin配置的例子
2.2 直接添加过滤器

Spring Security 参考手册https://www.springcloud.cc/spring-security-zhcn.html#true-

Spring Security 提供大量的示例应用 lots of sample applications 使用-jc参数演示使用java配置Spring Security。
https://github.com/spring-projects
官网推荐的例子等

Spring Security 实战干货 系列文章
https://www.felord.cn/categories/spring-security/

这个系列的文章比较全,理论为主
注意:需要加博主微信获取验证码

Spring Security【系列文章】

4篇文章简单入门,适用大部分使用场景

集成QQ登录和微信登录简单逻辑。代码不全,先收藏借鉴。
源码位置补充:https://gitee.com/guohtime/springboot-security-social
采用springboot-security-social实现第三方认证

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        formAuthenticationConfig.configure(http);
        http
                .csrf().disable()//关闭跨站防护
                .apply(validateCodeSecurityConfig) //校验验证码
                    .and()
                .apply(smsCodeAuthenticationSecurityConfig)//手机验证码登陆
                    .and()
                .apply(sociaSecurityConfig) //第三方登陆
                    .and()
                .authorizeRequests()//下面授权配置
                    .antMatchers(
                            SecurityConstants.DEFAULT_UNAUTHENTICATION_URL, //处理登陆请求
                            SecurityConstants.DEFAULT_SIGN_IN_PROCESSING_URL_MOBILE, //手机登陆
                            securityProperties.getBrowser().getLoginPage(), //登陆页面
                            securityProperties.getBrowser().getSignUpUrl(), //注册页面
                            SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX + "/*", //验证码
                            "/user/regist")//第三方注册跟绑定
                            .permitAll()//login请求除外不需要认证
                    .anyRequest()
                    .authenticated()//所有请求都需要身份认证
                    .and()
                .rememberMe() //记住密码
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds()) //失效时间
                    .userDetailsService(userDetailsService)
                    .and()
                .sessionManagement()
                    .invalidSessionStrategy(invalidSessionStrategy) //session失效后的处理
                    .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions()) //用户最大登陆数
                    .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())//是否阻止登陆
                    .expiredUrl(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL)//用户只能登陆一次
                    .expiredSessionStrategy(sessionInformationExpiredStrategy)//用户被挤掉后的处理
                    .sessionRegistry(sessionRegistry)
                    .and()
                    .and()
                .logout()
                    .logoutUrl("/sigOut")//默认退出路径是logOut可以自定义
                    .logoutSuccessHandler(logoutSuccessHandler)//处理退出到类
                   //.logoutSuccessUrl("/login")//退出后跳到到页面
                    .deleteCookies("JSESSIONID");


    }

源码或者原理说明

认证流程

在这里插入图片描述

关键类

  • UsernamePasswordAuthenticationFilter。用户名和密码认证过滤器

public class UsernamePasswordAuthenticationFilter extends
AbstractAuthenticationProcessingFilter ;

 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
            String username = this.obtainUsername(request);
            String password = this.obtainPassword(request);
            if (username == null) {
                username = "";
            }

            if (password == null) {
                password = "";
            }

            username = username.trim();
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }

UsernamePasswordAuthenticationToken


public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 520L;
    private final Object principal;
    private Object credentials;

    public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
        this.setAuthenticated(false);
    }

    public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }

    public Object getCredentials() {
        return this.credentials;
    }

    public Object getPrincipal() {
        return this.principal;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        } else {
            super.setAuthenticated(false);
        }
    }

    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }
}

源码过程分析直接参考Spring boot + Spring Security 多种登录认证方式配置(一)https://blog.csdn.net/qq_36521507/article/details/103365805
不再重复贴源代码了。

Spring Security多种登录方式集成

要实现一个登录认证,首先要自定义一个过滤器 AbstractAuthenticationProcessingFilter,注入一个认证管理器 AuthenticationManager,然后需要绑定一个AbstractAuthenticationToken,注册一个认证处理器 AuthenticationProvider,如果使用默认认证过滤器,则只需要自定义认证处理器进行认证即可.

参考文章: Spring boot + Spring Security
多种登录认证方式配置(一)

https://blog.csdn.net/qq_36521507/article/details/103365805 Spring
boot + Spring Security
多种登录认证方式配置(二)
https://blog.csdn.net/qq_36521507/article/details/103370070

应用场景:对接已有的认证系统特别是个性化的第三方认证系统。如果是LDAP、AUTH2等默认有集成,例子比较多。

Security + Vue 实现前后端分离登录

SpringBoot系列(六)SpringBoot 集成 Security + Vue 实现前后端分离登录https://blog.csdn.net/baidu_37832943/article/details/101064508

贴近项目实际情况的一个例子
有源代码和例子。 页面登录+验证码验证功能。

实现验证码校验

SpringSecurity之添加过滤器

案例:实现验证码校验
1.使用过滤器实现验证码校验

总结

【参考Spring实战】

编写简单的安全性设置

SpringSecurity必须配置在一个实现了WebSecurityConfigurer的bean中,或者扩展WebSecurityConfigurerAdapter(简单方式)。
编写一个子类实现自定义配置或者实现。
这里的配置是关键

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter;

重载configure()方法

方法 描述
configure(WebSecurity) 配置Filter链
configure(HttpSecurity) 配置拦截器保护请求
configure(AuthenticationManagerBuilder) 配置user-detail服务
 public static class SmsLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .apply(smsCodeAuthenticationSecurityConfig) //短信登陆配置
                    .and()
                    .authorizeRequests()
                    .antMatchers("/code/*").permitAll()
                    .antMatchers("/api/*").permitAll()
                    .anyRequest().authenticated()
            .and()
                    //这里配置的为当未登录访问受保护资源时,返回json
                    .exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPointHandler());
            ;
        }
    }

.apply(),可以配置另外一个WebSecurityConfigurerAdapter 子类;
.and() .authorizeRequests().antMatchers("/code/*").permitAll()使用Ant风格配置方式配置/code/请求路径的不认证也能访问,也就是不拦截请求。
.anyRequest().authenticated()代表后续请求需要认证后才能访问。

配置自定义用户服务(认证逻辑)

实现UserDetailsService 和UserDetails 接口,用于获取用户和角色信息。

这里就比较灵活了,不管是采用jdbc、redis、ldap或者通过resttemplate从第三方接口获取数据都是可以的。

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

//角色赋值例子
    private List<String> roles;

 @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (roles == null || roles.isEmpty()) {
            return new ArrayList<>();
        }

        List<GrantedAuthority> authorities = new ArrayList<>(roles.size());
        for (String role : roles) {
            authorities.add(new SimpleGrantedAuthority(role));
        }

        return authorities;
    }

实现后的UserDetailsService 配置在configure(AuthenticationManagerBuilder) 下,例如:

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new UserDetailServiceImpl());
    }
发布了25 篇原创文章 · 获赞 7 · 访问量 922

猜你喜欢

转载自blog.csdn.net/m0_46485771/article/details/105104471