哈哈,我又来了。这个springsecurity可折腾死我了,别的我觉着用不着记录,这个必须记录。去年搞了这个框架代替了自己写的权限机制,一是为了随大流,二是自己写的有线程问题。这下好了,遇到点新问题就不会解决,已解决就过了三天,弱爆了。
最近有一个旧系统,业务庞大,光数据表400多个,需要移植,一点点从原来的.net平台移植到java平台,这就涉及到两个平台的集成,自己写了个集成方案,旧系统访问新系统时就被springsecurity拦住了,按照网上的配置了放行无效果,人家都是springboot集成,代码配置,我时xml配置,也有人家自定义过滤器的,不过说的不明白,参杂了业务处理又缺代码,但是也给了我启示,特别有用的启示,一会把文章链接放上来。
先说我的解决方案:
1、就是请求传递一个标志,在标准的FILTER_SECURITY_INTERCEPTOR过滤器中分类处理,跨域的一波,正常的一波。正常的就不说了,我也是照抄的。跨域的也不用多写无用的代码,能用已经有的就用已经有的。例如:
//_requesType是跨域请求标志
if(request.getParameter("_requesType")!=null&&session.getAttribute("SPRING_SECURITY_CONTEXT")==null) {
//调用了已经定义好的登录过滤器,里面有证书、权限等各种处理
AuthenticationFilter filter = (AuthenticationFilter) SpringContextUtil.getApplicationContext().getBean("loginFilter");
//获取证书
Authentication authentication= filter.attemptAuthentication(request, response);
//放到上下文中,这一步很重要,不然第一次跨域可以访问,跨过去以后的url也还是被拦截
SecurityContextHolder.getContext().setAuthentication(authentication);
session.setAttribute("SPRING_SECURITY_CONTEXT",SecurityContextHolder.getContext());
//调用了启动时就执行的整理角色、资源的类,这个类处理权限配对的,因为角色和资源有动态配对情况,为方便这个类里有更新证书的方法
MySecurityMetadataSource securityMetadataSource = (MySecurityMetadataSource) SpringContextUtil.getBean("securityMetadataSource");
securityMetadataSource.updateSource(session);
//然后就通过了
chain.doFilter(req, res);
return;
}
这一步参考:https://blog.youkuaiyun.com/lvhao2813/article/details/81974242
2、上一步中有个更新证书的方法,如下:
/**
* 重载缓存,更新资源
*/
public static void updateSource(HttpSession session){
//重载缓存
requestMap.clear();
//调用工厂中已有的角色类,找所有角色
IResourceService resourceService = (IResourceService) SpringContextUtil.getApplicationContext().getBean("resourceService");
//找所有资源
List<Resource> resourceList = resourceService.searchFlat(null,null).getRows();
//配对
for(Resource resource:resourceList)
{
AntPathRequestMatcher matcher = new AntPathRequestMatcher(resource.getAction());
List<ConfigAttribute> roleList = new ArrayList<ConfigAttribute>();
for(Object ob:resourceService.findRoleList(resource.getResourceId()))
{
SecurityConfig config = new SecurityConfig(((Role)ob).getName());
roleList.add(config);
}
requestMap.put(matcher, roleList);
}
//更新当前用户角色
SecurityContext context = (SecurityContext)session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication authentication = context.getAuthentication();
OnlineUser user = (OnlineUser)authentication.getPrincipal();
//修改后的新权限,authority里放的是rolename
IRoleService roleService = (IRoleService) SpringContextUtil.getApplicationContext().getBean("roleService");
List<String> roleNameList = roleService.findRoleNameByUserId(user.getUserID());
String[] tempList = new String[roleNameList.size()];
for(int i=0; i<roleNameList.size();i++){
tempList[i]=roleNameList.get(i);
}
List<GrantedAuthority> authoritiesList = AuthorityUtils.createAuthorityList(tempList);
user.setAuthorities(authoritiesList);
//更新token,给证书
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(),authoritiesList);
authenticationToken.setDetails(authentication.getDetails());
context.setAuthentication(authenticationToken);
resourceList.clear();
roleNameList.clear();
}
这一步年代久远,参考的找不见了。
解决方法主要适用于前后端分离,一次请求的url大于一个的情况,如果是一个的话很简单。