Simple implementation of Shilo single sign on

Mode one multiple login

  1. sso method of MVC Controller
@RequestMapping(value = "ssoLogin.do")
public String sso(String userName, String password,HttpServletRequest request, HttpServletResponse response) {
	AuthUser user = userDao.getUserByname(userName);
	 UsernamePasswordToken token = new UsernamePasswordToken(username, password);
	 //Get the current Subject
     Subject currentUser = SecurityUtils.getSubject();
	 currentUser.login(token);
	currentUser.getSession("true").setAttribute("userName",userName);//shrio session
	currentUser.getSession().setAttribute("loginName",userName);//http session
	return "xxx"; //page
}
  1. call
String path = "osdp";//request.getContextPath(); / / project address
String basePath = request.getScheme() + ":" +  request.getServerName() + ":" +  request.getServerPort() + path;//url
String userName = UserHolder.getUserName();
String password =  UserHolder.getPassword();
String data = "userName="  + userName + "&password="  + password;
return "redirect:" +  basePath + "/ssoLogin" + "?" + data;

Mode 2 custom Token token

  1. sso method of MVC Controller mapping
  /**
	* Single sign on (jump directly if already signed in)
	* @param userCode Login user code
	* @param token Login token, token composition: sso key + user name + date, md5 encryption, for example:
	* String secretKey = Global.getConfig("shiro.sso.secretKey");
	* String token = Digests.md5(secretKey + userCode + DateUtils.getDate("yyyyMMdd"));
	* @param url The url address of the jump after successful login.
	* @param relogin Whether to log in again, need to log in again to pass true
	* For example: 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 you are already logged in
	if(principal != null){
		// If set to force log in again, log in again
		if (BooleanUtils.toBoolean(relogin)){
			SecurityUtils.getSubject().logout();
		}
		// Otherwise, go directly to the target page
		else{
			return "redirect:" + Encodes.urlDecode2(url);
		}
	}
	// Single sign on
	if (token != null){
		UsernamePasswordToken upt = new UsernamePasswordToken();
	try {
		upt.setUsername(userCode); // Login user name
		upt.setPassword(token.toCharArray()); // Password composition: sso key + user name + date, MD5 encryption, for example: Digests.md5(secretKey+username+20150101))
		upt.setParams(upt.toString()); // Single sign on identification parameter, see: AuthorizingRealm.assertCredentialsMatch
	} catch (Exception ex){
		if (!ex.getMessage().startsWith("msg:")){
			ex = new AuthenticationException("msg:Authorization token error, please contact the administrator.");
		}
		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:Authorization error, please check the user configuration, if it can not be resolved, please contact the administrator.");
		}
		model.addAttribute("exception", ae);
		}
	}
	return "error/403";
}
  1. Overloads the assertCredentialsMatch method of org.apache.shiro.realm.AuthorizingRealm class
/**
* Authentication password matching call method
*/
@Override
protected void assertCredentialsMatch(AuthenticationToken authcToken,
	AuthenticationInfo info) throws AuthenticationException {
	UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
	// If single sign on, single sign on authorization method is used.
	if (token.toString().equals(token.getParams())){
		// sso key + user name + date, MD5 encryption, for example: 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. Realize Shiro stateless access, such as session access by passing sessionid parameter
public class SessionManager extends DefaultWebSessionManager {
	public SessionManager() {
		super();
	}
	@Override
	protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
		// This sid session is used if the parameter contains the "\. For example: http: / / localhost / project? sid = XXX &? Cookie = true
		// In fact, the following parameters can also be used here: session name in the cookie: for example: JSESSIONID=xxx, in the path; JESSIONID=xxx, but it is recommended to use the \.
		String sid = request.getParameter("__sid");
		if (StringUtils.isNotBlank(sid)) {
			// Whether to save sid to cookie, this parameter is used in browser mode.
			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);
			}
			// Set current session state
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
			ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session source and 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);
		}
	}
}
  1. call
String path = "osdp";//request.getContextPath(); / / project address
String basePath = request.getScheme() + ":" +  request.getServerName() + ":" +  request.getServerPort() + path;//url
String userName = UserHolder.getUserName();
String secretKey = "SSO";
String token =   DigestUtils.md5Hex(secretKey + userName + CommonUtil.getToday());
String data = "userName="  + userName + "&token="  + token;
return "redirect:" +  basePath + "/ssoLogin" + "?" + data;

Note: shiro configuration release single point request: / sso** =anon

The above two methods can realize simple single sign on. The basic idea is to log in multiple subsystems once (user-defined token login or user name password login, the principle is the same). Multi point logout means that every sub item should also be logout once:

SecurityUtils.getSubject().logout();//Write off oneself
HttpUtil.get("xxx/logout");//Interface: log off other projects at the same time

Tags: Programming Session Shiro Apache

Posted on Wed, 18 Mar 2020 07:36:58 -0700 by daneth1712