单点登录是什么?
一个系统中可能会引用别的很多系统。单点登录就是解决,一次登录,就可以访问所有的系统。
每次浏览器向一个域名发送http请求,会去查找域名的cookie信息拼接到http的header中发送到服务器。
cookie不能跨域。这个域是浏览器请求的域名,哪怕他们都是访问一个服务器也不能跨越。
网上有很多基于spring boot的Spring Security OAuth2.0的单点登录,以及Shiro的单点登录
接下来我也会去学习并且去搭建一个sso
上面都是基于认证服务器和客户端的。
我这里无法去构造做认证服务器,以及客户端。。只是实现单点登录这种功能,包括安全等等都是非常危险的,这里只是讲原理。
背景:我们这里有一个基于spring boot的报表项目,里面集成了spring security进行安全防护。我们另一个很老的系统,需要实现单点登录,它那里登录之后,可以访问报表项目。
这个方式可能不好,目前只是基于单点登录原理的一个实例,以后可以写出更好的单点登录。
一、基于老系统,它登录成功后即可以访问报表系统。我们单独开放白名单,让老系统可以访问,并将用户名传递,此时我们已经认为这个用户是登录成功的。在报表系统,我们需要根据用户名来查询密码,模拟登录。例如:xxxx/outIndex?username=admin
二、基于报表系统。我们收到请求。spring security会拦截我们的请求(outIndex?username=admin),因为白名单允许访问。这里我们模拟登录。
这里我们就需要简单了解一下spring security。我们这里需要跳过它的验证。如何跳过呢,我们来自己构造身份信息。让springSecurity认为已经登录过了。
spring security主要是通过一系列的filter进行安全验证的。
这里WebSecurityConfigurerAdapter是我们自定义的配置文件。这个类用来配置spring security的,所以在启动的时候回执行这个类。
那么我们需要构造一个filter来拦截outIndex请求,拦截到请求后进行构造身份信息。
将身份信息放入上下文,以及session中。这样我们就相当于登录过了。
filter代码
@WebFilter(filterName = "ssoLoginFilter", urlPatterns = { "/*" })
public class SsoLoginFilter implements Filter {
@Autowired
private IPriManagerService userManagerService;
@Autowired
private IPriRoleService userRoleService;
@Autowired
public IPriOrganizationService priOrganizationService;
@Autowired
public IPriMenuService priMenuService;
@Value("${fine.report.path}")
public String fineReportPath;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if ("/outIndex".equals(req.getRequestURI())) {
String username = request.getParameter("username");
// 根据用户名username加载userDetails
PriManagerBean priManager = new PriManagerBean();
priManager.setUserCode(username);
priManager = userManagerService.checkManager(priManager);
User user = new User(username, priManager.getPassword(),
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
// 根据userDetails构建新的Authentication,这里使用了
// PreAuthenticatedAuthenticationToken当然可以用其他token,如UsernamePasswordAuthenticationToken
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user,
user.getPassword(), user.getAuthorities());
// 设置authentication中details
authentication.setDetails(new WebAuthenticationDetails((HttpServletRequest) request));
// 存放authentication到SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(authentication);
HttpSession session = ((HttpServletRequest) request).getSession(true);
// 在session中存放security context,方便同一个session中控制用户的其他操作
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
session.setAttribute(Constants.PRI_MANAGER, priManager);
session.setAttribute(Constants.FINE_REPORT_PATH, fineReportPath);
setHomeUrl(session, priManager);
setMenu(session, priManager);
setUserRole(session, priManager);
setRole(session, priManager);
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: setUserRole
* </p>
* <p>
* Description: 保存用户角色
* </p>
*
* @param session
* @param priManager
*/
private void setUserRole(HttpSession session, PriManagerBean priManager) {
session.setAttribute(Constants.PRI_USER_ID, priManager.getMgrId());
session.setAttribute(Constants.PRI_USER_LEVEL, priManager.getIsSuper());
session.setAttribute(Constants.PRI_USER_ROLE, userManagerService.queryUserRole(priManager.getMgrId()));
}
private void setRole(HttpSession session, PriManagerBean priManager) {
session.setAttribute(Constants.PRI_ROLE, userRoleService.findRoleByMrgId(priManager.getMgrId()));
}
private void setMenu(HttpSession session, PriManagerBean priManager) {
List<PriMenuBean> menuList = null;
List<Map<String, String>> menuOptList = null;
if (SessionUtil.isSuper(session)) {
menuList = userManagerService.queryAllMenu();
} else {
Map<String, String> formMap = new HashMap<String, String>(16);
formMap.put("LOGIN_MGR_ID", priManager.getMgrId());
menuList = priMenuService.queryMenuListByLevel(formMap);
}
if (menuList != null) {
menuOptList = userManagerService.queryMenuAndOptByUser(priManager);
}
session.setAttribute(Constants.PRI_MENU_OPT, menuList);
session.setAttribute(Constants.PRI_MENUE_MENU_OPT, menuOptList);
session.setAttribute(Constants.FORMAT_TODAY, LoginUtil.getTodayFormat());
}
private void setHomeUrl(HttpSession session, PriManagerBean priManager) {
String queryHomeUrl = userManagerService.queryHomeUrl(priManager.getMgrId());
session.setAttribute(Constants.HOME_URL, StringUtils.isEmpty(queryHomeUrl) ? "/index" : queryHomeUrl);
}
}