shiro 实现多种方式登录_shiro单点登录的简单实现

本文介绍了使用Shiro实现单点登录的两种方法:一种是基于多次登录,另一种是自定义Token令牌。通过MVC Controller的方法详细展示了登录逻辑,并提供了重载`assertCredentialsMatch`方法来验证凭证。此外,还讨论了如何实现Shiro无状态访问,以及多点注销的处理方式。
摘要由CSDN通过智能技术生成

方式一 多次登录

MVC Controller 的 sso 方法

@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);

//获取当前的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"; //页面

}

调用

String path = "osdp";//request.getContextPath();//项目地址

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;

方式二 自定义Token令牌

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";

}

重载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");//接口:同时注销其他项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值