Spring cloud微服务安全实战-3-13重构代码

让代码同时支持两种方式,登陆访问和带着请求头的token访问也可以。

首先做代码的重构

这里改成getSession() 改成这样以后会有一个问题,我用httpBasic登陆成功以后,我的用户信息放在session里面,后续的请求不用带Authorization的请求头也能访问。
我希望实现的效果是,如果你没登陆,那么你用HttpBasic这种方式来访问,每次你的头里面都要带着这个。然后除非你登陆了,访问的时候才可以不带这个头。那么要达到这个效果的话,我们需要来分辨下,哪些session是通过httpBasic这种方式建立的session。
像下面的这个getSesison就是通过httpBasic这种方式建立的。

还有一种是调用登陆方法,在登陆方法里面创建的session

想到达的效果就是,在httpBasic这种方式创建出来的session,在他方法调用结束以后,返回的时候把这个session销毁掉。
那么下次他再上来的时候session就没了。他就必须手里带着一个token,才能再啦访问这个请求。
那么要达到这个效果,就是在这里写个try finally

把过滤器的调用放在try里面。把过滤器的调用放在try里面。然后在finally里面让他失效掉。

这么写还有个问题就是登陆的那块的session也会失效掉。所以我需要做一个判断。在httpBasic的session中多加一个temp的session。判断它不为空, 就让session失效掉。

这样我们现在即支持登陆来访问也支持httpBasic访问


用UserInfo去接收

这里获取session里面的user改用UserInfo去接收了。那么存session的地方也要存成UserInfo这个类。、存的时候调用user.buildInfo()方法,转换成UserInfo对象即可。



原来在user写的方法要挪一下


把这段代码剪切到UserInfo里面




把这个属性也复制过去,注意是复制,不是剪切。

SecurityConfig

之前这里是写死的,现在我明确知道我要从session里面拿用户信息

那么Spring有一种静态的方法,可以让我们拿到session

强制转换。




从serveltRequestAttribute我们就可以拿到当前的request,再从request里拿到session


现在这个AuditorWare就可以根据真正的用户是谁,就可以拿到它的用户名来并返回。最终审计日志的时候,是当前登陆的用户名了。。


@Bean
public AuditorAware<String> auditorAware(){
return new AuditorAware<String>() {
@Override
public Optional<String> getCurrentAuditor() {
ServletRequestAttributes servletRequestAttributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
UserInfo info=(UserInfo)servletRequestAttributes.getRequest().getSession().getAttribute("user");
String username=null;
if(info!=null){
username=info.getUsername();
}
//return Optional.of("jojo");
return Optional.ofNullable(username);
}
};
}
 


以上就重构完成了。

做退出操作

让session失效。UserController里面增加一个logout的方法

@GetMapping("/logout")
public void logout(HttpServletRequest request){
request.getSession().invalidate();//sessin失效
}


然后这里也改成UserInfo


@GetMapping("/{id}")
public UserInfo get(@PathVariable Long id, HttpServletRequest request) throws Exception {
UserInfo user=(UserInfo) request.getAttribute("user");

if(user == null || !user.getId().equals(id)) {
throw new RuntimeException("身份认证信息异常,获取用户信息失败");
}
return userService.get(id);
}
 


修正自己代码的两处问题

一是在登陆的时候,UserController里面 往session存UserInfo对象的时候,写错了。这里之前是取的user对象,然后存的时候也是存user。 后面存的时候我自己忘了改了。 后来跟了下代码 发现是这里的问题。

二是在退出登陆的时候,要把退出的请求路径加入到排除列表里面。这样可以直接访问到logout,然后清空session。

运行系统

filter里面没有明显的是哪些代码是请求进来的时候调用,哪些代码是响应回去的时候调用,这样看起来不直观,不如拦截器的方法

拦截器的preHandler和afterCompletion看起来直观。 


现在是没带请求头也没登陆过。直接访问users/13 所以返回的是401

http://localhost:8080/users/13



带上我们的请求头

带上请求头就拿到用户信息了。


把请求头删掉依然不能访问,说明httpBasic每次请求响应回去session都被清除了。

测试登陆




登陆成功后,不带请求头访问我们的方法,因为我们是登陆过的,服务器端存了session

调用一下退出的方法

退出后,再调用getUser方法


以上就实现了我们想要的效果,我们这个方法支持两种认证方式。方法过程中有流控、身份认证、有审计、有授权等等
所有的安全机制应该都已经具备了。、

结束

原文地址:https://www.cnblogs.com/wangjunwei/p/11930488.html