spring boot中spring security实现单点登录,传统模式(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvhao2813/article/details/81974242

单点登录是什么?

一个系统中可能会引用别的很多系统。单点登录就是解决,一次登录,就可以访问所有的系统。

每次浏览器向一个域名发送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);
	}
}

猜你喜欢

转载自blog.csdn.net/lvhao2813/article/details/81974242