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

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的具体实现)

发布了7 篇原创文章 · 获赞 7 · 访问量 1848

猜你喜欢

转载自blog.csdn.net/TheJam/article/details/104756120