Spring Security的使用 #Web安全#权限认证《Spring实战》第4版笔记 (一)

本文介绍了Spring Security的基本概念,包括其过滤Web请求的机制、简单的安全性配置以及用户信息查询服务的选择,如内存存储、数据库认证和LDAP认证。在配置过程中强调了密码编码的重要性,建议避免明文存储密码,推荐使用加密算法。

9.1 Spring Security简介

Spring Security 是基于Spring AOP和Servlet规范中的Filter实现的安全框架,能够在Web请求级别和方法调用级别处理身份认证和授权。

Spring Security 从两个角度来解决安全性问题。它使用Servlet 规范中的Filter的保护Web请求并限制URL级别的访问。Spring Security 通过使用Spring AOP 保护方法调用——借助于对象代理和使用通知,能够确保只有具备适当权限的用户才能访问安全保护的方法。

9.1.1 Speing Security的模块

9.1.2 过滤Web请求

通过web.xml或者AbstractSecurityWebApplicationInitializer的子类配置 DelegatingFilterProxy,都会拦截发往应用中的请求,并将请求委托给ID为 springSecurityFilterChain 的bean。

9.1.3 简单的安全性配置

@Configuration
@EnableWebSecurity  // ->启用web应用的安全性功能
public class SecurityConfig extends WebSecurityConfigurerAdapter{
}

使用SpringMVC开发,则用 @EnableWebMvcSecurity替代@EnableWebSecurity,通过重载 WebSecurityConfigurerAdapter的是哪个configure()方法来配置Web安全性。

方法描述
configure(WebSecurity)通过重载,配置Spring Security的Filter链
configure(HttpSecurity)通过重载,配置如何通过拦截器保护请求
configure(AuthenticationManagerBuilder)通过重载,配置user-detail服务

默认的configure(HttpSecurity) 代码

prorected void configure(HttpSecurity http) throws Exception{
   http
     .authrizeRequests()
       .anyRequest().authenicated()  // 所有进入应用的HTTP请求都要验证
       .and()
     .formLogin().add() // 支持基于表单的登录以及HTTP Basic方式的认证
     .httpBasic();  
}
//单没有用户存储支撑认证过程,没有用户存储,实际上就等于没有用户,没人能登录成功
  • 配置用户存储
  • 指定哪些请求需要认证,哪些请求不需要认证,以及所需要的权限;
  • 提供一个自定义的登录界面,替代原来简单的默认登录页。

9.2 选择查询用户信息的服务

9.2.1 基于内存的用户存储

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication() //启用内存用户存储
                .withUser("user").password("password").roles("USER").and()
                .withUser("admin").password("password").roles("USER","ADMIN");
    }
}

配置用户详细信息的方法

方法描述
accountExpired(boolean)定义账号是否已经过期
accountLocked(boolean)定义账号是否已经锁定
and()用来连接配置
authorities(GrantedAuthority…)授予某个用户一项或多项权限
authorities(List<? extendsGrantedAuthority…> )授予某个用户一项或多项权限
authorities(String…)授予某个用户一项或多项权限
credentialsExpired(boolean)定义凭证是否已经过期
disabled(boolean)定义账号是否已被禁用
password(String)定义用户的密码
roles(String…)授予某个用户一项或多项角色

以上方法在学习实现过程中,发现了已经有几个地方出现了更改
1.@EnbaleWebMvcSecurity已被启用 -> 改为@EnableWebSecurity
2.执行测试之后出现异常

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
	at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:250) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$LazyPasswordEncoder.matches(WebSecurityConfigurerAdapter.java:592) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]

测试成功的代码

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) //启用内存用户存储
                .withUser("user").password(new BCryptPasswordEncoder().encode("password")).roles("USER").and()
                .withUser("admin").password(new BCryptPasswordEncoder().encode("password")).roles("USER","ADMIN");
    }
}

9.2.2 基于数据库表进行认证

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    DataSource dataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth
                .jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(
                        "select user_id,user_pwd,true from t_user where user_id=?" 
                )
                .authoritiesByUsernameQuery(
                        "select user_id,'ROLE_USER' from t_user where user_id=?"
                )
                .passwordEncoder(NoOpPasswordEncoder.getInstance());
               //.passwordEncoder(new BCryptPasswordEncoder());
    }
}

注意 passwordEncoder( )这个方法,Spinrg实战第4版给讯息:Spring Security的加密模块包括了三个这样的实现:BCryptPasswordEncoder、NoOpPasswordEncoder和StandardPasswordEncoder,也可以自己实现特定的加密解密算法。
不管使用那一个密码转码器,都需要劣迹一点,数据库中的密码是永远不会解码的。所采取的的策略与之相反,用户在登录时输入的密码会按照相同的算法进行转码,然后再与数据库中已经转码过的密码进行对比。

简单的说就是 如果你数据库中存的是明文密码,即假设123456,那是不需要这个属性的,使用NoOpPasswordEncoder!但是这个“无”加码器与后面的那个标准解码器在新版本的Spring Security已经被弃用了,但是出于安全考虑的启用,官方推荐不要使用明文存储密码 。

所以要么使用启用的No··Encoder 要么在数据库存储的数据就采用算法进行加密

9.2.3 基于LDAP进行认证

9.2.4 配置自定义的服务

如果内置的用户存储无法通用认证需求时,才有配置自定义的必要,假设用户存储在NoSQL中

public class SpitterUserService implements UserDetailsService {

    @Autowired
    private SpitterRepository spitterRepository;  //注入

    @Override
    public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
        Spitter spitter=spitterRepository.findByUserId(userId);  //查找Spitter
        if(spitter!=null){
            List<GrantedAuthority> authorities=new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority("ROLE_SPITTER")); //创建权限列表
            return new User(   //返回User
                spitter.getUserId(),
                spitter.getUserPwd(),
                authorities);
            }
        throw new UserIdNotFoundException();
        }
    }
}
@Autowired
SpitterRepository spitterRepository;
@Override
protected void configure(AuthenticationManagerBuilder auth) throw Exception{
   auth.userDetailsService(new SpitterUserService(spitterRepository));
}

通过实现UserDetailsService 可以不管用户数据在哪,只会查找Spitter对象,甚至可以伪造一个,也不用关心底层所使用的数据存储,只是获得Spitter对象,并用它来创建User(User是UserDetails的具体实现)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值