1.主要作用是 认证和授权
2.底层是过滤器链
3.导入 springSecurity 场景启动器后,spring启动,自动配置生效
过滤器如何加载的
1.SecurityFilterAutoConfiguration
@bean
Delegating FilterProxyRegistrationBean(注册了 DelegatingFilterproxy(filter))
执行它的 doFilter()
delegateTouse = this.initDelegate(webApplcaiitonContext)
Filter delegate = wac.getBean(filterChainproxy,Filterclass)
创建 filterchainProxy实例并获得
delegate.init(this.getFilterconfig())
执行filterchainproxy的 dofilter()
filterchainproxy里面有个 list<SecurityFilterChain>里面有关于security的全部过滤器
filterchainProxy.doFilter()
doFilterInternal()
List<Filter> filters = this.getFilters()
遍历List<SecurityFilterchain>
if(chain.matches(request)){
return chain.getFilters()
}能匹配 request的 filter全部 返回
后将这些 filter全部 加到我们的 filterchain中
======================================================
delegatingFilter 的 doFilter 就是获得 filterchain(里面包含那10几个 security的 filter)
注意,这个delegatingFilter的 doFilter是 在springboot容器启动就执行的,目的就是
将Filter全部加到 filterchain中,便于后面过滤请求
重要的三个过滤器
1.FilterSecurityInterceptor
是一个方法级的 权限过滤器,基本位于 过滤器的 最底部
1 dofilter()
fi = new FilterInvocation()
invoke(fi)
判断上一个 filter的 doFilter是否 执行了 chain.doFilter() 执行了
fi.getchain().doFilter()
它的doFilter的意思,就是判断上一个 filter的 chain.doFilter()是否执行
执行了,那么这个filter 直接 执行下一个filter 的 doFilter()
2.ExceptionTranslationFilter
是一个异常过滤器,用来处理在认证过程中抛出的异常
1. doFilter()
try{
chain.doFilter()
}catch(Exp e){
throw e;抛出异常
}
在下面过滤中,认证和授权,是在下面的过滤链中完成的,
只要下面的过滤出现了异常,那么在这一层捕捉
3.usernamePasswordAuthenticationFilter
对 /login
的 post请求
做拦截,检验表单的 用户名密码
是否
正确
1.dofilter()
authResult = attemptAuthentication(req,resp)'
if authResult = null return filterchain直接结束
else sessionStrategy.onAuthentication(authResult,req,resp)
2.所以,我们这里 关注 attemptAuthentication()即可
但是,这里的是默认的校验,我们需要 写一个 usernamePasswordAuthenticationFilter的 子类
并且 重写 attemptAuthentication()方法,完成自定义username,password校验
3.重写的 attempAuthentication()
1. 判断 是否是 post请求 不是 直接 return
2. 得到 request中的 username和 password
3. 注意:前端传过来的 参数名 必须是 username和 password
因为,我们这过滤器已经写死了
4.UserDetaliService接口实现类loadUserByUsername() 查询 datebase 中的 username和password
如果查询得到,那么封装成 User(Security提供的)返回,user中包括了 权限和角色
5.用passwordEncoder接口 将前端的password加密后,和user的 password作比较
如果相等,那么认证成功
6.userDetailService只负责返回User,或者直接return,或者抛异常(因为user有可能查询不到
那就没有后面 认证成功的需要了,直接在这里结束即可)
后面的 认证 包括用passwordEncoder给 前端密码加密,都是springSecurity做的,他负责判断是否
认证成功
7.认证成功,跟授权没有半毛钱,认证成功代表 User登入了,授权只是说,这个User有没有访问这个
路径的权限,但是登入是已经登入成功了的,下一次访问无需再次认证
两个重要接口
1.UserDetialsService接口
UserDetalis loadUserByUsername(String name)
在这个方法里面查用户,并判断调用 PasswordEncoder的matchs方法
判断密码是否正确,最后 return User(user)
2.PasswordEncoder接口
encode(password) 将密码加密
mathces(password)方法,将加密的方法,和 user的password作比较
相等,return true
BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,平时多使用这个解析器。
重点:userDetailService的作用,就是返回 一个User,它的调用不用我们管
返回User后,再跟前端传来的做比较,这一步也不归我们管
同样PasswordEncode给前端 密码加密,也不归我们管,我们只用在
auth里面提供,userDetailService,和passwordEncode就行
3.就算我们不 重写 一个 usernamepasswordAuthenticationFilter
我们就写注册 一个 passwordEncoder的实现类,重写里面里面的方法
在默认的 filter中也会,调用 它的 encode方法,给密码加密
然后再比较
4.给前端密码加密,是springSecurity帮我们做的,不用我们自己做,我们只用提供在配置类的configure方法里面提供,
password接口即可
passwordEncoder使用时机的详解
1.springSecurity有一个默认的passwordEncoder
2.在User返回后,springSecurity会调用 passwordEncoder的 matches方法,去匹配User里面的password
和前端传来的password(当然我们需要对前端传来的 password加密)
3. passwordEncoder的2个方法
1.String encode(CharSequence charSequence 这个是对前端password的封装)
这个方法,如果是我们提供的 passwordEncoder,完全可以不用
因为springSecurity只会调用 matches方法,只是默认的passwordEncoder会在 matches方法里面
调用encode() 方法,去给 前端passworde 加密
2.boolean matches(CharSequence charSequence , String encodedpassword)
charSequene 代表 前端password的封装,一般要charSequence.toString(),再去加密
encodedpassword 是 dataBase中 存储的password(一般都是加密了的)
我们需要在这个方法将 charSequence.toSrting做一个加密后和 encodedpassword做一个比较
然后 return boolean,如果 return true 代表 认证成功
注意:加密方式需要和 database中储存的password的加密方式一样
web权限方案
1.用户认证
这三种方式本质都是在 auth里面设置用户名密码,角色,权限
或者设置,userDetailService,PasswordEncoder,
真正 拿User 和 前端的 作比较…不用我们管
1.配置文件,修改默认username 和 password
spring.security.user.name=username
spring.security.user.password=password
这样默认用户名密码就改了,这样执行到 filter的时候,就会用
前端的用户名和密码 和 这个改了的 去比较
2.配置类
在springbootWebSecurityCOnfiguration中
默认支持 DefaultConfigurerAdapter
前提是在 缺少 WebSecurityConfigureAdapter的情况下
现在我们自己注册一个,WebSecurityConfigurerAdapter的实现类
就可以用我们自己的
重写 void configure(AuthenticationManagerBullder auth)方法
这个方法,可以设置我们的 默认用户名,密码,roles
auth.inMemoryAuthentication().writerUser().password().roles();
3.自己编写,userDetialsService和passwordEncoder(最常用)
1.将userDetialsService和passwordEncoder 注入ioc容器中
2.在配置类中 autowired这两个组件
3.在配置类的 void configurer(AuthenticationManangerBuilder auth)中
auth.userDetailsService().passwordEncoder(),将这两个组件 set进 auth
4.这样,我们就可以在 userDetailsService中完成 User的 return(不能return user,那后面的认证都不需要了
直接结束)
User返回后,后面passwordEncoder给前端密码加密,然后认证这不是我们需要管的
我们要做的 就是在 userDetailsService中,将User返回
User
代表了,return的用户,里面有用户的userName,password,以及List《GrantedAuthority》
注意 GrantedAuthority代表 auth,相当于代表Role和权限(Authority),List《GrantedAuthorit》就代表了,
这个User,拥有这个 Role/权限的 集合
认证和授权是两个方面的,返回User,然后SpringSecurity去认证,认证时不看角色和权限,就看用户名和密码是否对应,是,代表认证成功,代表登入了,User中的(角色和权限),代表User的角色和权限,授权是 配置类的configure(HttpSecurity)中设置的,角色权限不通过,代表不能访问此路径,但是认证是通过了的,下次访问角色和权限允许的那就可以访问了,但是不用再次认证
关于配置类中的,configure(HttpSecurity http)和configure(AuthticationManangerBuilder auth)的区别
1.configure(AuthticationManangerBuilder auth)里面主要是设置,我们返回User的实现类,已经将前端密码加密的
passwordEncoder,换句话说,就是设置我们要给springSecurity做认证的 User
2.configure(HttpSecurity http)里面主要是设置,在认证的过程中的一些 SpringSecurity的功能的一些设置
比如,设置登入页面,登入成功后跳转的路径,哪些路径不需要认证,哪些路径需要权限.....
configure(HttpSecurity http)里面一些具体设置
(loginPage("/index") // 配置哪个 url 为登录页面
.successForwardUrl("/success") // 登录成功之后跳转到哪个 url
.failureForwardUrl("/fail");// 登录失败之后跳转到哪个 url,
上面三个是说,如果请求直接 访问登入页面,那么登入成功即认证成功后跳转到哪个页面)
(如果是,直接访问的 请求地址,中间需要做认证,认证成功后,就会直接访问请求地址****了,不会再跳转到成功页面了)
protected void configure(HttpSecurity http) throws Exception {
//登入设置
http.formLogin()
.loginPage("/index") // 配置哪个 url 为登录页面
.successForwardUrl("/success") // 登录成功之后跳转到哪个 url
.failureForwardUrl("/fail");// 登录失败之后跳转到哪个 url
(上面三个,是说,如果请求直接 访问登入页面,那么登入成功即认证成功后跳转到哪个页面)
(如果是,直接访问的 请求地址,中间需要做认证,认证成功后,就会直接访问请求地址了,不会再跳转到成功页面了)
//关于 认证路径,和权限角色设置
http.authorizeRequests()
.antMatchers("/layui/**","/index").permitAll() //表示配置请求路径无需认证
.antMatchers("/layui/**","/index").hasRole("")
表示User只能有 这一个角色(User中的 GrantedAuthority只能是 一个这个角色才能授权访问)
.antMatchers("/layui/**","/index").hasAnyRole("","")
表示User可以有这其中的 任意一个角色即可
(注意配置文件中不需要添加”ROLE_“,因为上述的底层代码会自动添加与之进行匹配)
(但是,new GrantedAuthority("ROLE_"+"")这个必须加上ROLE,才能和springSecurity的比较
因为spirngSeucrity底层.antMatchers("/layui/**","/index").hasRole("") 是将""加上了ROEL_
再和 User中的 GrantedAuthority("") 中的 ""比较的 )
=================================================================
.antMatchers("/layui/**","/index").hasAuthority("")
表示User只能有 这一个权限(User中的 GrantedAuthority只能是 一个这个权限才能授权访问)
.antMatchers("/layui/**","/index").hasAnyAuthority("","")
表示User可以有这其中的 任意一个权限即可
.anyRequest().authenticated(); // 其他请求需要认证
// 关闭 csrf
http.csrf().disable();
}
(注意配置文件中不需要添加”ROLE_“,因为上述的底层代码会自动添加与之进行匹配)
(但是,new GrantedAuthority(“ROLE_”+"")这个必须加上ROLE,才能和springSecurity的比较
因为spirngSeucrity底层.antMatchers("").hasRole("") 是将"“加上了ROEL_
再和 User中的 GrantedAuthority(”") 中的 ""比较的 )
用户注销
1.在配置文件的 protected void configure(HttpSecurity http) 中
http.logout.logoutUrl("注销地址").logoutSuccessUrl("注销成功地址").permitAll();
注销地址不是任何资源,只是一个url字符串,在页面设置这个 url,
你点击,就会注销成功,并跳转到注销成功的地址
2.当你注销成功后,你的User相当于被注销了,没有User了,下次得再次 认证
3.用户注销,实际上调用的是tokenMananger的 移除cookie中(或者header中的cookie),那么下次访问的时候
无法获得token字符串,那么就算用户注销了,就得重新认证了
认证成功后,再次访问其他路径,就不用再次认证了,除非关闭浏览器
spring实现自动登入(浏览器关闭,也能自动登入)
技术点:cookie+springSecurity机制实现自动登入
注意:在登入页面添加 自动登入复选框,name必须是 remember-mc
我们只需要完成上述配置,其他的springSecurity帮我们做了
自动登入底层原理
首先,不管我们有没有配置自动登入,我们都会走上面这个流程,都会生成token字符串,都会加入到cookie中…,只是一点我们配置配的是啥,就是配置的 cookie的有效时间
1.添加复选框,我们勾选了,传了 remember-me,参数,代表可以走下面的 自动登入的流程了
2.在配置类中配置,PersisterTokenReposity组件,因为SpirngSecurity底层在 userDetailsService认证成功后
会调用 这个 组件去保存cookie,和 存数据库
3.在 配置类的 cofigue(HttpSecurity)方法中
设置 persisterTokenReposity和cookie时长,以及userDetailsService,代表 PersisterTokenReposity是在
userDetalsService中 执行的