Spring Security文章梳理

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

参考文章

SpringBoot集成Spring Security

Spring Security 入门原理及实战https://www.cnblogs.com/demingblog/p/10874753.html

教科书级别的介绍,补充了解

【置顶】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/

这个系列的文章比较全,理论为主
注意:需要加博主微信获取验证码
博主相关文章的另外链接 cnblogs里,不全
https://www.cnblogs.com/felordcn/p/12142557.html

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");


    }

用户自定义登录逻辑

https://www.cnblogs.com/ifme/p/12155796.html

  1. 处理用户信息获取逻辑 UserDetailsService
  2. 处理用户校验逻辑 UserDetails
  3. 处理密码加密解密 PasswordEncoder

源码或者原理说明

认证流程

在这里插入图片描述

关键类

  • 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());
    }

加密

Spring Security 进阶-加密篇 https://segmentfault.com/a/1190000018625960

Spring Security 为我们提供了一套加密规则和密码比对规则,org.springframework.security.crypto.password.PasswordEncoder 接口,该接口里面定义了三个方法。

public interface PasswordEncoder {

    //加密(外面调用一般在注册的时候加密前端传过来的密码保存进数据库)
    String encode(CharSequence rawPassword);

    //加密前后对比(一般用来比对前端提交过来的密码和数据库存储密码, 也就是明文和密文的对比)
    boolean matches(CharSequence rawPassword, String encodedPassword);

    //是否需要再次进行编码, 默认不需要
    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

其中常用到的分别有下面这么几个

BCryptPasswordEncoder:Spring Security 推荐使用的,使用BCrypt强哈希方法来加密。
MessageDigestPasswordEncoder:用作传统的加密方式加密(支持 MD5、SHA-1、SHA-256…)
DelegatingPasswordEncoder:最常用的,根据加密类型id进行不同方式的加密,兼容性强
NoOpPasswordEncoder:明文, 不做加密
其他

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值