shiro单点登录的简单实现

主宰稳场 提交于 2020-03-18 16:23:26

某厂面试归来,发现自己落伍了!>>>

一 自定义Token令牌

  1. MVC Controller 映射 sso 方法
  /**
	* 单点登录(如已经登录,则直接跳转)
	* @param userCode 登录用户编码
	* @param token 登录令牌,令牌组成:sso密钥+用户名+日期,进行md5加密,举例:
	* String secretKey = Global.getConfig("shiro.sso.secretKey");
	* String token = Digests.md5(secretKey + userCode + DateUtils.getDate("yyyyMMdd"));
	* @param url 登录成功后跳转的url地址。
	* @param relogin 是否重新登录,需要重新登录传递true
	* 例如:http://localhost/project/sso/{token}?url=xxx&relogin=true
	*/
@RequestMapping(value = "sso/{userCode}/{token}")
public String sso(@PathVariable String userCode, @PathVariable String token,@RequestParam(required=true) String url, String relogin, Model model) {
	Principal principal = SecurityUtils.getSubject().getPrincipal();
	// 如果已经登录
	if(principal != null){
		// 如果设置强制重新登录,则重新登录
		if (BooleanUtils.toBoolean(relogin)){
			SecurityUtils.getSubject().logout();
		}
		// 否则,直接跳转到目标页
		else{
			return "redirect:" + Encodes.urlDecode2(url);
		}
	}
	// 进行单点登录
	if (token != null){
		UsernamePasswordToken upt = new UsernamePasswordToken();
	try {
		upt.setUsername(userCode); // 登录用户名
		upt.setPassword(token.toCharArray()); // 密码组成:sso密钥+用户名+日期,进行md5加密,举例: Digests.md5(secretKey+username+20150101))
		upt.setParams(upt.toString()); // 单点登录识别参数,see: AuthorizingRealm.assertCredentialsMatch
	} catch (Exception ex){
		if (!ex.getMessage().startsWith("msg:")){
			ex = new AuthenticationException("msg:授权令牌错误,请联系管理员。");
		}
		model.addAttribute("exception", ex);
	}
	try {
		SecurityUtils.getSubject().login(upt);
		return "redirect:" + Encodes.urlDecode2(url);
	} catch (AuthenticationException ae) {
		if (!ae.getMessage().startsWith("msg:")){
			ae = new AuthenticationException("msg:授权错误,请检查用户配置,若不能解决,请联系管理员。");
		}
		model.addAttribute("exception", ae);
		}
	}
	return "error/403";
}
  1. 重载org.apache.shiro.realm.AuthorizingRealm类的assertCredentialsMatch方法
/**
* 认证密码匹配调用方法
*/
@Override
protected void assertCredentialsMatch(AuthenticationToken authcToken,
	AuthenticationInfo info) throws AuthenticationException {
	UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
	// 若单点登录,则使用单点登录授权方法。
	if (token.toString().equals(token.getParams())){
		// sso密钥+用户名+日期,进行md5加密,举例: Digests.md5(secretKey+username+20150101))
		String secretKey = Global.getConfig("shiro.sso.secretKey");
		String password = Digests.md5(secretKey + token.getUsername() + DateUtils.getDate("yyyyMMdd"));
		if (password.equals(String.valueOf(token.getPassword()))){
			return;
		}
	}
	super.assertCredentialsMatch(token, info);
}
  1. 实现Shiro无状态访问,如通过传递sessionid参数即可实现会话访问
public class SessionManager extends DefaultWebSessionManager {
	public SessionManager() {
		super();
	}
	@Override
	protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
		// 如果参数中包含“__sid”参数,则使用此sid会话。 例如:http://localhost/project?__sid=xxx&__cookie=true
		// 其实这里还可以使用如下参数:cookie中的session名称:如:JSESSIONID=xxx,路径中的 ;JESSIONID=xxx,但建议还是使用 __sid参数。
		String sid = request.getParameter("__sid");
		if (StringUtils.isNotBlank(sid)) {
			// 是否将sid保存到cookie,浏览器模式下使用此参数。
			if (WebUtils.isTrue(request, "__cookie")){
				HttpServletRequest rq = (HttpServletRequest)request;
				HttpServletResponse rs = (HttpServletResponse)response;
				Cookie template = getSessionIdCookie();
				Cookie cookie = new SimpleCookie(template);
				cookie.setValue(sid); cookie.saveTo(rq, rs);
			}
			// 设置当前session状态
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
			ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session来源与url
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
			return sid;
		}else{
			return super.getSessionId(request, response);
		}
	}
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!