前言:
通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往复以至无穷,而实践和认识之每一循环的内容,都比较地进到了高一级的程度
温故知新:
正片:
第四篇:认识SpringSecurity认证框架(下)
第五篇:
第四篇:认识SpringSecurity认证框架(下)
标题为Access Currently Authenticated User——访问当前已验证的用户
在上一期,我们体验官方的Security认证模型(框架),如何定义的
在这一期,我们将体验SecurityContextHolder承担完登录,认证后的内容
逻辑推演:
认证完后的内容,存储在SecurityContextHolder内的SecurityContext中的Authentication中
那么,我们要读出存储在Authenticaiton的内容该怎么办?
第一:获取SecurityContext内容
第二:获取Authentication的内容
第三:获取详细信息
发现没,这就是创建的倒用,对比一下
第一:通过SecurityContextHolder创建EMptyContext内容
第二:创建Authenticaiton详细认证内容
第三:将Authentication设置为Context内容
第四:将Context内容设置为SecurityContextHolder内容
其中第三与第四可以合成一步,但是在官方文档中是不建议这么做的,因为会导致线程竞争
看到官方的示例
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
第一步:获取SecurityContext ✔
第二步:获取Authentication ✔
第三步:针对需要的内容去获取剩下的三部分 ✔
对比自定义Context
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication =
new TestingAuthenticationToken("username", "password", "ROLE_USER");
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
第一步:创建EmptyContext
第二步:创建Authentication
第三步:设置ContextHolder
在对比中,我们可以发现,Authenticaiton认证是基于SecurityContext的,而SecurityContext是基于SecurityContextHolder
也是十分符合认证框架图,SecurityContextHolder在最底层,Authentication在最顶层,在这一期,我们将体验SecurityContextHolder在完成一个完整的认证循环后的内容
这么大费周章的去描述这个内容,为了更好看懂下面这个BUG
在运行这段代码时,我们碰见了Security第一个报错
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.springframework.security.core.Authentication.getName()" because "authentication" is null
线程 “main” java.lang.NullPointerException 中出现异常:无法调用 “org.springframework.security.core.Authentication.getName()”,因为 “authentication” 为 null
为什么会导致该内容为空的?
因为SecurityContextHolder没接受到认证用户信息,导致Context为空,最终导致Authentication为空!
知道了为什么报错,就知道怎么解决
这里作者想到了三种
第一种:SecurityContextHolder成功接受内容
第二种:自定义一个登录认证代码,完成SecurityContextHolder
这两种方法都离不开SecurityCOntextHolder,因为没有Holder就没有Context,懂不懂Security authentication认证地基含金量!
实践
第一种:让SecurityContextHolder成功接受内容
答案:因为报错,无法运行客户端,导致无法接受信息,死局!
第二种:自定义一个登入认证代码
答案:由于作者水平,导致无法实践
那这个就不能管了吗?有一句话说的好,发现问题是代码你有能力,解决问题靠的是态度,而不是技术!
我就在第一种方法上,修改了,既然没办法直接调用,因为Holder必为空,也就是死局,那我能不能让他先登录,再去调用呢?
结合上MVC框架,哦,懂了,我们可以将这段内容编写成一个接口,先完成登录功能,再去调用接口,接口再去完成Holder → context →Authentication的循环,返回Context
理论可行,实践开始
实践结果
打印出来了,和创建时的差不多
差不多,代表了,代码也差不多
废话,打印的都是基于Authenticaion的,能差不多吗!!!!!!!
疑问,既然能打印出单独的属性,那么我直接打印context可以吗?
实践开始
内容SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=user, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, CredentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=1D1D1BFC6CA26B03307193822580EAAD], Granted Authorities=[]]]
Contest里面包含很多内容
既然可以打印这个,不妨试试Authentication的全部GEt方法的内容
我们打印了Authentication的区别内容+Context
发现没,这个用户名和密码是不属于用户明细的
代码运行完了,下面的说明没啥好看的,总结下来就两个字,勿动,六个字,勿动默认配置
总结:第四篇上下
第一:Security认证架构(专业点,模板阿,框架阿,都差不多)一切基于SecurityContextHolder,Authentication基于Context
第二:解决问题靠的是态度,而不是能力