shiro 流程大概总结:
JSP:
配置loginUrl,在此URL返回的视图里,会有个form(此form无须指明action,我想是因为配置了loginUrl的关系,但是配置了authc 为loginUrl),提交后,就会进入FormAuthenticationFilter,你可以重写他,处理自己的逻辑,如写response为JSON的,等等。这样如果登陆成功了,会根据之前访问的URL,和配置的SUCCEEURL作为备选,优先是去之前的URL,(有个疑问,如果之前的是login,那现在登陆成功后还是login?或者处理了下如果是login就返回备选URL,如果没有配successUrl呢,是不是应该有什么必须的东西再里面)。这样就访问到之前的URL了,一般都是/,就是首页了,controller里面定义下这个这个返回方法就行(可以写个mainController,用来处理首页的。有时候还可以把 / 配置成重定向到另外一个controler,不提了)
JSON:
上面都是JSP的,不适合EXT,同样需要配置loginUrl,登陆操作不是用form来了,用ajax提交的,同样配置了authc 为loginUrl,同样进FormAuthenticationFilter,这时候肯定要重新它了,让它返回JSON,自己在JS sucess里面回调重定向到首页(wecome/index/home 这种名字的)。
还有个注意的,所谓的shiro权限字符串(如 "admin:session:forceLogout"),这玩意没什么特别的地方,就是一个ID,一个有意义的ID,我之前一直以为shiro会怎么处理它,发现就是ID而已,甚至可以用 其他什么ID来代替它,这玩意就是用来唯一标识一个权限的。一般可以在controller里面方法上面 加入注解 @RequiresPermissions("admin:session:forceLogout")(也可以在页面上用shiro 标签 包裹某段代码,用以实现该段代码是否显示)。
(上面这段错了,还是有意义的,shiro会用通配符来匹配,两边进行equals,
@Override public boolean implies(Permission p) { if(!(p instanceof BitPermission)) { return false; } BitPermission other = (BitPermission) p; if(!("*".equals(this.resourceIdentify) || this.resourceIdentify.equals(other.resourceIdentify))) { return false; } if(!(this.permissionBit ==0 || (this.permissionBit & other.permissionBit) != 0)) { return false; } if(!("*".equals(this.instanceId) || this.instanceId.equals(other.instanceId))) { return false; } return true; }
,只有当是通配符,或者相等时候,返回 TRUE),就是分解,然后三个部分进行相等比较,三个部分表示
在spring-mvc配置文件里统一处理异常
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="java.lang.Exception">error/500</prop> <prop key="java.lang.RuntimeException">error/500</prop> <prop key="java.lang.Throwable">error/500</prop> <prop key="UnauthorizedException">error/noRealm</prop> </props> </property> <!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 --> <property name="warnLogCategory" value="WARN"></property> <!-- 默认错误页面,当找不到上面mappings中指定的异常对应视图时,使用本默认配置 --> <property name="defaultErrorView" value="error/500"></property> <!-- 默认HTTP状态码 --> <property name="defaultStatusCode" value="500"></property> </bean>
这里可能JSON的就不是这么处理了。(如果权限粒度只到菜单 这个返回页面的 ,不到操作按钮的这种AJAX 返回JSON的,是可以满足的)。
总结,主要还是AuthorizingRealm这个类,和FormAuthenticationFilter这个类
public class ShiroDbRealm extends AuthorizingRealm { private static Logger logger = LoggerFactory.getLogger(ShiroDbRealm.class); @Autowired protected AccountService accountService; /** * 认证回调函数,登录时调用. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { logger.info("doGetAuthenticationInfo----"); UsernamePasswordToken token = (UsernamePasswordToken) authcToken; User user = null; try { user = accountService.findUserByLoginName(token.getUsername()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } if (user != null) { byte[] salt = Encodes.decodeHex(user.getSalt());//16进制的 return new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(salt), getName()); // return new SimpleAuthenticationInfo(); } else { return null; } } /** * 设定Password校验的Hash算法与迭代次数. */ @PostConstruct public void initCredentialsMatcher() { HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(AccountService.HASH_ALGORITHM); matcher.setHashIterations(AccountService.HASH_INTERATIONS); setCredentialsMatcher(matcher); } /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String)principals.getPrimaryPrincipal(); //Authorization 授权,即权限验证,验证某个已认证的用户是否拥有某个权限 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); try { User user = this.userService.getUserByName(username); Set<String> roles = new HashSet<String>(); //本系统设计为一个用户属于一个用户组,即用户组就是用户的角色(employee、finance、hr、boss..);每个用户组有不同的权限(资源) //其他系统中可以设置 一个用户有多个角色,一个角色有多个权限 //在本系统中 除了管理员是admin其他组都用user标识,除了老板,其他用户组的操作都和员工组一样的。 roles.add("admin".equals(user.getGroup().getType())?"admin":"user"); List<GroupAndResource> grList = this.grService.getResource(user.getGroup().getId()); Set<String> resources = new HashSet<String>(); for(GroupAndResource gr : grList){ Resource resource = this.resourceService.getPermissions(gr.getResourceId()); if(!BeanUtils.isBlank(resource)){ resources.add(resource.getPermission()); } } authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(resources); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("realm 错误!"); } return authorizationInfo; } public void setAccountService(AccountService accountService) { this.accountService = accountService; }
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter { private static final Logger log = LoggerFactory .getLogger(CustomFormAuthenticationFilter.class); /** * 所有请求都会经过的方法。 */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (log.isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); } //验证码暂不处理 // if ("XMLHttpRequest" // .equalsIgnoreCase(((HttpServletRequest) request) // .getHeader("X-Requested-With"))) {// 不是ajax请求 // String vcode = request.getParameter("vcode"); // HttpServletRequest httpservletrequest = (HttpServletRequest) request; // String vvcode = (String) httpservletrequest // .getSession() // .getAttribute("com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY" // ); // if (vvcode == null || "".equals(vvcode) // || !vvcode.equals(vcode)) { // response.setCharacterEncoding("UTF-8"); // PrintWriter out = response.getWriter(); // out.println("{success:false,msg:'验证码错误'}"); // out.flush(); // out.close(); // return false; // } // } return executeLogin(request, response); } else { if (log.isTraceEnabled()) { log.trace("Login page view."); } // allow them to see the login page ;) return true; } } else { if (log.isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]"); } if (!"XMLHttpRequest" .equalsIgnoreCase(((HttpServletRequest) request) .getHeader("X-Requested-With"))) {// 不是ajax请求 saveRequestAndRedirectToLogin(request, response); } else { response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.println("{msg:'login'}"); out.flush(); out.close(); } return false; } } /** * 覆盖默认实现,用sendRedirect直接跳出框架,以免造成js框架重复加载js出错。 * @param token * @param subject * @param request * @param response * @return * @throws Exception * @see org.apache.shiro.web.filter.authc.FormAuthenticationFilter#onLoginSuccess(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.subject.Subject, javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ @Override protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { //issueSuccessRedirect(request, response); //we handled the success redirect directly, prevent the chain from continuing: HttpServletRequest httpServletRequest = (HttpServletRequest)request; HttpServletResponse httpServletResponse = (HttpServletResponse)response; if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With")) && request.getParameter("ajax") == null) {// 不是ajax请求 让他重定向到页面 issueSuccessRedirect(request, response); } else {//在ajax里面,用不了shiro配置的successurl重定向功能,只能在回调函数里重定向 wj 2016-9-7 httpServletResponse.setCharacterEncoding("UTF-8"); PrintWriter out = httpServletResponse.getWriter(); out.println("{success:true,msg:'登入成功'}"); out.flush(); out.close(); } return false; } /** * 主要是处理登入失败的方法 */ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { if (!"XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request) .getHeader("X-Requested-With"))) {// 不是ajax请求 setFailureAttribute(request, e); return true; } try { response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); String msg = e.getClass().getSimpleName(); if ("IncorrectCredentialsException".equals(msg)) { out.println("{success:false,msg:'密码错误'}"); } else if ("UnknownAccountException".equals(msg)) { out.println("{success:false,msg:'账号不存在'}"); } else if ("LockedAccountException".equals(msg)) { out.println("{success:false,msg:'账号被锁定'}"); } else { out.println("{success:false,msg:'未知错误'}"); } out.flush(); out.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } return false; }
,
相关推荐
【权限管理框架Shiro学习总结】 在IT领域,权限管理是一个关键的安全机制,它确保了只有合法的用户才能访问特定的资源。Apache Shiro是一个强大且易用的Java安全框架,提供认证、授权、会话管理和加密等功能。下面...
本总结将从 Shiro 的基本概念、验证和授权过程、加密方式和 JSP 标签等方面进行总结。 一、基本概念 1. Subject(主体):当前操作的用户。 2. SecurityManager(安全管理器):负责管理安全相关的操作,包含 ...
Apache Shiro 是一款Java安全框架,它提供了身份认证、授权、加密和会话...对于面试和学习来说,掌握Shiro的基本概念、架构以及核心功能,可以帮助开发者构建安全的Java应用,并且在面试时展现出扎实的安全管理知识。
通过本文档,将深入探讨 Shiro 的核心概念,并结合实际应用场景来理解其工作原理。 ##### 1.1 认证(Authentication) 认证是验证用户身份的过程,通常基于用户名和密码。在 Shiro 中,认证可以通过以下步骤完成:...
1. **Subject**:是Shiro的中心概念,代表了当前“安全的用户”。它提供了进行认证、授权、会话管理和事件监听的主要接口。 2. **Realms**: Realm是Shiro与应用安全数据源(如数据库)的桥梁,它负责验证凭证并...
这个“Shiro_学习总结.zip”文件包含了一个 PDF 文档,很可能是对 Shiro 框架核心概念、功能以及使用方法的详尽总结。 在 Shiro 中,主要涉及以下几个核心组件: 1. **认证(Authentication)**:这是验证用户身份...
总结一下,Struts2和Shiro的整合提供了完整的Web应用安全解决方案,包括用户认证、授权、会话管理和权限控制。通过合理配置和使用,开发者可以构建出安全、易用的Java Web应用。提供的压缩包"shirodemo"应包含了一个...
通过这个教程,你可以了解到Shiro的基本概念和API,为后续更深入的学习打下基础。 总结来说,Apache Shiro 是一个全面的安全框架,能够满足各种类型应用程序的安全需求,提供简洁的API来处理复杂的安全问题。无论是...
下面我们将深入探讨Apache Shiro的基本概念、常见攻击以及如何防范这些攻击。 **Apache Shiro框架** Apache Shiro的核心组件包括认证、授权、会话管理和加密。认证是验证用户身份的过程,授权则涉及决定用户是否有...
**Shiro框架核心概念** 1. **身份验证(Authentication)**:验证用户身份的过程,即确定用户是谁。 2. **授权(Authorization)**:也称为访问控制,决定用户是否有权限执行特定的操作或访问特定资源。 3. **会话...
总结一下,Shiro的核心组件包括: 1. Subject:代表用户。 2. SecurityManager:是Shiro的核心,协调各组件工作。 3. Authenticator:处理用户登录验证。 4. Authorizer:决定用户的角色和权限。 5. SessionManager...
Shiro 的核心概念包括主体(Subject)、安全管理者(SecurityManager)、身份验证(Authentication)、授权(Authorization)以及会话管理(Session Management)。 - **主体(Subject)**:代表当前用户,可以是...
首先,"shiro框架教案"部分可能涵盖了Shiro的基本概念、架构设计、核心组件如Subject、Realms、Caches等的讲解,以及如何配置和使用Shiro进行用户认证和权限授权。教案通常会以教学步骤的形式,逐步解析Shiro的工作...
本文将深入探讨 Shiro 的核心概念和功能,包括 sessionMode、realm、缓存策略以及它们在实际应用中的配置。 1. sessionMode 在 Shiro 中,sessionMode 决定了如何处理会话管理。在传统的 Web 应用中,可以选择使用 ...
1. Shiro通过Role(角色)和Permission(权限)的概念来进行授权。角色是一组权限的集合,权限则是对特定资源的操作。 2. 在系统初始化时,将用户的角色和权限加载到内存。 3. 当用户尝试访问资源时,Shiro会检查...
总结起来,"shiro权限管理实例"为我们提供了一个学习Shiro权限控制的实践平台。通过这个实例,我们可以了解如何设置身份验证、授权、会话管理和加密,这对于任何需要用户权限管理的Java应用都是非常有价值的。
Apache Shiro 是一个...总结,Apache Shiro 是一个功能丰富的安全框架,能够轻松处理认证、授权、加密和会话管理。通过对 `shiro-demo` 项目的理解和实践,你将能掌握 Shiro 的基本用法,并能在实际项目中有效运用。
通过上述知识点的学习,Java开发者及相关专业和技术爱好者将能够深入理解Shiro框架的核心概念与工作原理,并能够运用到实际项目开发中,实现用户认证、授权、加密等功能,从而提升项目的整体安全性和用户体验。
本教程旨在全面介绍 Apache Shiro 的基础知识和实践技巧,帮助开发者快速掌握 Shiro 的核心概念和技术细节,为实际项目中的安全控制提供坚实的基础。通过深入理解 Shiro 的架构和工作原理,开发者能够更加灵活地运用...
Realm是Shiro框架中的核心概念之一,它是Shiro与应用数据源之间的桥梁,负责加载用户信息、角色和权限。常见的实现方式包括JDBCRealm,适用于使用关系数据库的应用程序。此外还有CASRealm等其他类型的Realm,用于...