SpringSecurity是Spring大家族中解决认证授权问题的框架。
大家针对安全问题之前采用基于Session认证的方式,太过于繁琐,而且硬编码太严重,Security不仅可以做到Session所能实现的功能,而且依赖于Spring的Aop可以在不修改原有代码的前提下,提供安全保护。
接下来我用最简单的配置为我们的web应用配置SpringSecurity,配置完成后,体验之后,我再进行细节的说明。
前提是当前项目已经是web项目,并且有spring的相关依赖,再加入下面依赖即可,如果是sprigboot只需加入security的stater即可
org.springframework.security
spring‐security‐web
5.2.1.RELEASE
org.springframework.security
spring‐security‐config
5.2.1.RELEASE
之后对Security进行最简单的配置
//这个类实现了WebApplication接口,会自动被spring发现,并在web容器中注册DelegatingFilterProxy,这个代理类会是一个filter但他本身不会做什么,而是
//交给spring容器中的spirngSecurityFilterChain进行处理,你也可以大概理解这个代理连接起了Spring 与SpringSecurity,即使他看起来没什么特色
public class SecurityInit extends AbstractSecurityWebApplicationInitializer {
}
@Configuration
@EnableWebSecurity//启用spring对security的支持,其实也就是注册上面所说的springSecurityFilterChain
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()//表示启用http保护
.anyRequest().authenticated()//对所有请求需要认证
.and()
.formlogin();//表示允许用表单登录
}
}
进行过上面的配置,你只要重启应用,就会发现你被自动跳转到Security自动为你生成的登录页面(如果你发送/logout会发现也为你自动生成了退出登录功能),当然因为Security的版本不同这个页面会有所不同,但这不是你所真正关心的对吧。
但是很显然你根本没有写过一点关于账号密码的配置,
这个页面无法登陆进去,进下来我们进行账号密码的配置,我们需要在WebSecurityConfig中重写config(AuthentticationManagerBuilder auth)进行配置。
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("123").password("123").role("STUDENT");
}
但是你不觉得把所有请求都进行拦截有点严格了吗,
毕竟我们页面中的某些页面,
我们并不希望进行拦截,即使未认证我也能让用户看到,
所以我们可以进行更 细粒度的配置安全策略
我们更改一下刚才的配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/h").authenticated()//这个参数是字符串数组,你可以传入多个,你也可以继续.antMatcher进行配置
.and()
.formLogin();
}
这样我们就只对"/h"请求进行安全认证,其他的请求就会被放行,到这里我想你感觉到了,面向切面编程的好处,但现在为止我们没有修改原来web应用的代码,
只是加了一些关于安全认证的配置,感谢Spring的AOP吧!
,这些认证配置差不多满足你的需求,当然还有更多可能的实现,
比如限制用于的IP,限制请求的方式,甚至是使用SPEL表达式满足你的花里胡哨的需求,
我现在不会细说这些,如果你想更加深入了解,可以评论,如果有必要我会写。
你可能在想我的数据库的那么多用户,我总不能一个一个写上去吧,而且我的密码可能是加密过的,下面我们来解决一下这个问题
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
通过上面的这个配置其实就可以了,security自动会去我们去我们的数据查用户密码,
但是对我们的数据库表就有一些要求,如果有兴趣可以去查或者联系我,
接下来我会介绍一种更加通用的方式来和你的数据库交流,
你只需要声明一个bean如下
@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
@Autowired
StudentMapper studentMapper;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
Student student=studentMapper.findStudentByName(userName);
//这个User是Security提供的一个UserDetail的实现,我们可以直接用
return new User(student.getName(),student.getPassword(),"STUDENT");
}
}
通过上面的代码,当用户进行表单登录时,Security会帮我们拿着用户所提交的表单中的userName,调用USerDetailService实现类,
也就是我们刚刚写的这个类,来进行认证,通过这个类的loadUserByUsername方法,传入用户所提交的用户名,来查找数据库,
其实security并不关心我们这个方法的方法体是什么,他只关心我们最后返回的这个UserDetail的实现,也就是我们这里最后返回的User,
这是Security为我们提供的UserDetail的实现,Security会用我们最后返回的这个User里面的密码和用户表单提交的数据中的密码进行对比,
如果一样就会认为认证通过。
因为我们的数据库很多时候放的是加密后的密码,
那么认证的时候UserDetail中的密码就是加密后的,
我们任何时候都不会去解密我们的密码,
所以我们可以将表单提交过来的密码进行加密然后再和数据库进行对比就可以了
我们直接声明一个加密器bean,security就自动会使用这个加密器对表单数据中的密码进行
加密后再和UserDetail进行对比
//如果你的数据库密码是使用BCryot算法加密
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
我想你肯定感受到AOP技术的强大,我们应用似乎都不知道自己以及被保护了起来,
不过也是应用本身并不需要关心安全,它只需要做好自己的业务逻辑,
这也就是面向切面编程的优点