方式是一次登录好几次
MVC控制器的sso方法
@ request mapping (value=' SSO log in.do ' ) )。
公共字符串so (字符串用户名,字符串密码,http servlet请求请求,http servlet响应) {
authuser user=userdao.getuser by name;
usernamepasswordtokentoken=newusernamepasswordtoken (username,password );
//获取当前Subject
subject currentuser=security utils.get subject (;
currentuser.login(Token );
currentuser.getsession('true ) ).setattribute )、userName ); //shrio session
currentUser.getSession ().setattribute('loginname ',userName ); //http会话
返回' XXX '; //页面
}
框中,选择“默认值”
字符串路径=' osdp '; //request.getContextPath (; //项目地址
string basepath=request.getscheme (、' :' request.getServerName )、' :' request.getServerPort )和path; //url
string username=user holder.getusername (;
string password=user holder.get password (;
string data=' username=' username ' password=' password;
return ' redirect : ' basepath '/SSO log in '? 数据;
方式2自定义Token令牌
MVC控制器映射sso方法
//*
*单点登录(已登录时直接跳转) ) ) ) )。
* @ param用户代码登录用户代码
* @param token登录令牌,令牌配置: sso密钥用户名日期,md5加密。 示例:
* string secret key=global.getconfig (Shiro.SSO.secret key );
* string token=digests.MD5 (secretkeyusercodedateutils.getdate (yyyymmdd );
* @param url登录成功时要跳转的url地址。
* @param relogin是否要重新登录? 必须重新登录并传递true
*示例: http://localhost/project/SSO/{ token }? url=xxxrelogin=true
*/
@ request mapping (value=' SSO/{ user code }/{ token } )
公共字符串so (pathvariablestringusercode,@PathVariable String token,@requestparam ) required=true ) String url,striririable
principal principal=security utils.get subject ().getPrincipal );
//如果已经登录
if(principal!=空) {
//如果设置为强制重新登录,请重新登录
if (boolean utils.to boolean (relogin ) )。
SecurityUtils.getSubject ().logout );
}
//否则,直接跳转到目标页面
else{
return ' redirect : ' encodes.urldecode2(URL;
}
}
//单点登录
if(Token!=空) {
usernamepasswordtokenupt=newusernamepasswordtoken (;
try {
upt.se
tUsername(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";
}
重载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);
}
实现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);
}
}
}
调用
String path = "osdp";//request.getContextPath();//项目地址
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;
注意:shiro配置放开单点请求:/sso** =anon
以上两种方式可以实现简单的单点登录,基本思想就是多个子系统登录一遍(自定义token登录或用户名密码登录,原理一样)。
多点注销是,也要每一个子项目注销一遍:
SecurityUtils.getSubject().logout();//注销自己
HttpUtil.get("xxx/logout");//接口:同时注销其他项目
文章来源: www.oschina.net,作者:讓丄帝愛伱,版权归原作者所有,如需转载,请联系作者。
原文链接:https://my.oschina.net/u/2425659/blog/3197516