在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制
来源:互联网 发布:淘宝量子恒道统计 编辑:程序博客网 时间:2024/06/05 16:20
在前后端分离的项目中,ajax跨域和保存用户信息是其中的重点和难点。
如果在后台使用shiro框架来进行权限控制,就需要用到cookie+session的模式来保存用户的信息。
在前一篇文章《在前后端分离的项目中,ajax跨域请求怎样附带cookie》中,我具体写了怎样在ajax跨域的情况下携带cookie,使用该方法使跨域请求携带cookie便可以在前后端分离的项目中使用shrio的session(会话管理系统)。
但是由于那种方法近乎与取巧的将Access-Control-Allow-Origin由*改为"null"不是所有的前端ajax框架所公认的,我们需要一种更好的模式来使用session。
在传统的前后端分离模式中,我们通常是在请求头中增加一个请求头Authorization,它的值是一串加密的信息或者密钥,在后台通过对这个请求头值的读取,获取用户的信息。
而在这样的模式中,通常都是开发者自己设计的session或者加密方式来读取和保存用户信息,而在shiro中,集成了权限控制和用户管理在它的session系统中,这就意味着我们只能通过他所规定的session+cookie来保存用户信息,在这种情况下,该以什么方式在前后端分离的项目中使用shiro?
通过资料的查询,和对shiro设计模式的解读,我发现shiro和servlet一样实在cookie中存储一个session会话的id然后在每次请求中读取该session的id并获取session,这样就可以获取指定session中储存的用户信息。
我的想法就是通过重写shiro中获取cookie中的sessionId的方法来获取请求头Authorization中的密钥,而密钥储存的便是登录是返回的sessionId,从而实现在前后端分离的项目中使用shiro框架。
接下来就是代码演示(使用SpringMVC+Shiro),只贴出核心代码:
首先是登录的代码:
@ResponseBody @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json;charset=utf-8") public String login( @RequestParam(required = false) String username, @RequestParam(required = false) String password ) { JSONObject jsonObject = new JSONObject(); Subject subject = SecurityUtils.getSubject(); password = MD5Tools.MD5(password); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { // 登录,即身份验证 subject.login(token); onlineSessionManager.addOnlineSession(subject.getSession().getId()); User user = userService.getUserByLoginName(token.getUsername()); // 在session中存放用户信息 subject.getSession().setAttribute("userLogin", user); jsonObject.put("error", 0); jsonObject.put("msg", "登录成功"); // 返回sessionId作为token jsonObject.put("token",subject.getSession().getId()); } catch (IncorrectCredentialsException e) { throw new JsonException("用户名或密码错误", 405); } catch (LockedAccountException e) { throw new JsonException("登录失败,该用户已被冻结", 405); } catch (AuthenticationException e) { throw new JsonException("用户名或密码错误", 405); } return jsonObject.toString(); }然后重写DefaultWebSessionManager的getSessionId方法
package com.cangshi.shiro.ssesion;import org.apache.shiro.web.servlet.ShiroHttpServletRequest;import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;import org.apache.shiro.web.util.WebUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import java.io.Serializable;/** * Created by Palerock */public class SessionManager extends DefaultWebSessionManager { private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class); private String authorization = "Authorization"; /** * 重写获取sessionId的方法调用当前Manager的获取方法 * * @param request * @param response * @return */ @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response) { return this.getReferencedSessionId(request, response); } /** * 获取sessionId从请求中 * * @param request * @param response * @return */ private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) { String id = this.getSessionIdCookieValue(request, response); if (id != null) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "cookie"); } else { id = this.getUriPathSegmentParamValue(request, "JSESSIONID"); if (id == null) { // 获取请求头中的session id = WebUtils.toHttp(request).getHeader(this.authorization); if (id == null) { String name = this.getSessionIdName(); id = request.getParameter(name); if (id == null) { id = request.getParameter(name.toLowerCase()); } } } if (id != null) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "url"); } } if (id != null) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); } return id; } // copy super private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) { if (!this.isSessionIdCookieEnabled()) { log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie."); return null; } else if (!(request instanceof HttpServletRequest)) { log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie. Returning null."); return null; } else { HttpServletRequest httpRequest = (HttpServletRequest) request; return this.getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response)); } } // copy super private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) { if (!(servletRequest instanceof HttpServletRequest)) { return null; } else { HttpServletRequest request = (HttpServletRequest) servletRequest; String uri = request.getRequestURI(); if (uri == null) { return null; } else { int queryStartIndex = uri.indexOf(63); if (queryStartIndex >= 0) { uri = uri.substring(0, queryStartIndex); } int index = uri.indexOf(59); if (index < 0) { return null; } else { String TOKEN = paramName + "="; uri = uri.substring(index + 1); index = uri.lastIndexOf(TOKEN); if (index < 0) { return null; } else { uri = uri.substring(index + TOKEN.length()); index = uri.indexOf(59); if (index >= 0) { uri = uri.substring(0, index); } return uri; } } } } } // copy super private String getSessionIdName() { String name = this.getSessionIdCookie() != null ? this.getSessionIdCookie().getName() : null; if (name == null) { name = "JSESSIONID"; } return name; }}在重写这个方法的时候,调用了一个父类的私有方法,然而私有方法是不能重写的,所以重写的目的在于调用子类的同名私有方法也就是getReferencedSessionId方法,在这个方法中就是获取sessionId的步骤,在里面调用了三个父类的私有方法,getSessionIdCookieValue、getUriPathSegmentParamValue、getSessionIdName,也就是我使用copy super标注的部分,这部分是我复制父类的方法,让在不使用ajax的情况下能够正常使用cookie+session模式,而我们在步骤中加入从请求头中获取sessionId的部分也就是:
// 获取请求头中的sessionid = WebUtils.toHttp(request).getHeader(this.authorization);当该id 存在就不从cookie中获取id,自然达到了通过Authorization请求头获取sessionId并获取session的目的。
接下来就是Spring中xml中的配置会话管理器
<!-- 会话管理器 --><bean id="sessionManager" class="com.cangshi.shiro.ssesion.SessionManager"> <!--其它相关设置--></bean>这样我们在跨域的ajax请求中登录获取token,然后在接下来的请求的请求头中加上Authorization:[token]就可以使用shrio所自带的会话管理器,从而使用shiro的权限控制。
- 在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制
- 在前后端分离的SpringBoot项目中集成Shiro权限框架
- 在前后端分离的项目中,ajax跨域请求怎样附带cookie
- AngularJS实现前后端分离模式下的权限控制
- 前后端分离时保持前端的cookie一直都是一个从而让后端session是同一个
- 前后端分离时保持前端的cookie一直都是一个从而让后端session是同一个
- 前后端分离的权限控制
- ssh项目整合shiro时,在struts2的action中使用shiro的注解进行权限控制时,NoSuchMethodException:com.sun.proxy.$Proxy26
- Web项目开发中SESSION(会话)的使用
- 项目权限控制的管家——Apache Shiro框架
- 安全控制框架Shiro的使用
- 如何在spring项目中使用shiro进行权限管理
- 前后端分离项目:后台管理
- 关于富文本编辑器ckeditor在前后端分离项目中的使用
- JavaWeb项目:Shiro实现简单的权限控制(整合SSM)
- 使用shiro实现权限控制学习总结
- 使用拦截器或者AOP实现权限管理(OA系统中实现权限控制)
- 实现前后端分离的mock!!!mock的使用
- C++ 中宏(macro)#,##,和...(可变参数宏variadic macros)
- Ubuntu 下关闭/启用触摸板
- expandableListView嵌套GridView
- C++ 中Template 类、函数的编译过程
- Java Web 中通过request请求头获取客户端真实IP
- 在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制
- 转:Windows文件关联和VC实现
- Loaders 的使用,结合Fragments
- Skill: TightVNC Server: 重置密码
- 【线程】--基础知识
- Druid:一个用于大数据实时处理的开源分布式系统
- 交通银行闪退问题
- ajax post 提交中文java后台获取参数出现乱码解决方法
- linux日志管理