之前写过一篇博客:拦截器实现基于Url的权限管理,文章中讲解了怎么用拦截器实现url权限认证,这仅仅是权限管理的一部分。今天这篇博客就来说说一个项目完整的权限认证流程。

1、 准备权限数据

服务器启动时,通过InitListener监听器,将数据库中的权限信息查询出来,并放到ServletContext中。其中权限信息分两类:顶层菜单(系统管理)和其他权限信息url。ServletContext中放一些共享数据。

public class InitListener implements ServletContextListener {public void contextInitialized(ServletContextEvent sce) {// 获取容器与相关的Service对象ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());PrivilegeService privilegeService = (PrivilegeService) ac.getBean("privilegeServiceImpl");// 准备数据:topPrivilegeListList<Privilege> topPrivilegeList = privilegeService.findTopList();sce.getServletContext().setAttribute("topPrivilegeList", topPrivilegeList);System.out.println("------------> 已准备数据 <------------");// 准备数据:allPrivilegeUrlsCollection<String> allPrivilegeUrls = privilegeService.getAllPrivilegeUrls();sce.getServletContext().setAttribute("allPrivilegeUrls", allPrivilegeUrls);System.out.println("------------> 已准备数据allPrivilegeUrls <------------");}public void contextDestroyed(ServletContextEvent arg0) {}
}

2、编写拦截器CheckPrivilegeInterceptor,拦截用户的所有请求

public class CheckPrivilegeInterceptor extends AbstractInterceptor {public String intercept(ActionInvocation invocation) throws Exception {// 获取信息User user = (User) ActionContext.getContext().getSession().get("user"); // 当前登录用户String namespace = invocation.getProxy().getNamespace();String actionName = invocation.getProxy().getActionName();String privUrl = namespace + actionName; // 对应的权限URL// 如果未登录if (user == null) {if (privUrl.startsWith("/user_login")) { // "/user_loginUI", "/user_login"// 如果是去登录,就放行return invocation.invoke();} else {// 如果不是去登录,就转到登录页面return "loginUI";}}// 如果已登 录,就判断权限else {if (user.hasPrivilegeByUrl(privUrl)) {// 如果有权限,就放行return invocation.invoke();} else {// 如果没有权限,就转到提示页面return "noPrivilegeError";}}}}

3、其中User实体提供两个权限判断方法

hasPrivilegeByName( ):判断本用户是否有指定名称的权限,主要查询用户拥有哪个菜单权限,从而显示到页面

hasPrivilegeByUrl( ):判断本用户是否有指定URL的权限,主要是界面的增删改查权限url

    /*** 判断本用户是否有指定名称的权限* 主要查询用户拥有哪个菜单权限,从而显示到页面* @param name,菜单名称* @return*/public boolean hasPrivilegeByName(String name){// 超级管理有所有的权限if (isAdmin()){return true;}// 普通用户要判断是否含有这个权限for (Role role : roles){for (Privilege priv : role.getPrivileges()){if (priv.getName().equals(name)){return true;}}}return false;}------------------------华丽的分割线-------------------------/** 判断本用户是否有指定URL的权限* * @param privUrl  主要是界面的增删改查权限url* @return*/public boolean hasPrivilegeByUrl(String privUrl) {// 超级管理有所有的权限if (isAdmin()) {return true;}// >> 去掉后面的参数int pos = privUrl.indexOf("?");if (pos > -1) {privUrl = privUrl.substring(0, pos);}// >> 去掉UI后缀if (privUrl.endsWith("UI")) {privUrl = privUrl.substring(0, privUrl.length() - 2);}// 如果本URL不需要控制,则登录用户就可以使用//allPrivilegeUrls是在监听器中添加的Collection<String> allPrivilegeUrls = (Collection<String>) ActionContext.getContext().getApplication().get("allPrivilegeUrls");if (!allPrivilegeUrls.contains(privUrl)) {return true;} else {// 普通用户要判断是否含有这个权限for (Role role : roles) {for (Privilege priv : role.getPrivileges()) {if (privUrl.equals(priv.getUrl())) {return true;}}}return false;}}

4、 用户进行登录操作

首先进行登录校验,不成功给出提示;成功之后,将用户的信息放入到session中

    /** 登录 */public String login() throws Exception{User user = userService.findByLoginNameAndPassword(model.getLoginName(), model.getPassword());if (user == null){addFieldError("login", "用户名或密码不正确!");return "loginUI";}else{// 登录用户,将登陆用户放入sessionActionContext.getContext().getSession().put("user", user);return "toIndex";}}

5、用户登录之后显示首页的菜单信息

页面显示菜单信息,需要调用session.user.hasPrivilegeByName(name)方法判断是否有权限显示,其中topPrivilegeList是在初始化监听器时放入的顶级菜单信息。

<ul id="MenuUl"><%-- 显示一级菜单,在初始化时用Listener添加到ServletContextEvent中 --%><s:iterator value="#application.topPrivilegeList"><s:if test="#session.user.hasPrivilegeByName(name)"><li class="level1"><div onClick="menuClick(this);" class="level1Style"><img src="style/images/MenuIcon/${id}.gif" class="Icon" />${name}</div><ul style="" class="MenuLevel2" id="aa"><%-- 显示二级菜单 --%><s:iterator value="children"><s:if test="#session.user.hasPrivilegeByName(name)"><li class="level2"><div class="level2Style"><img src="style/images/MenuIcon/menu_arrow_single.gif" /><a target="right" href="${pageContext.request.contextPath}${url}.action"> ${name}</a></div></li></s:if></s:iterator></ul> </li></s:if></s:iterator></ul>

6、用户点击某个页面

用户点击某个页面,权限判断需要有两步,一是页面显示权限,而是url访问权限。

①修改Struts2的页面显示类AnchorTag ,添加判断:如果没有权限的话,就不显示该标签,让用户根本看不到。比如添加按钮等。

    /** $Id: AnchorTag.java 768855 2009-04-27 02:09:35Z wesw $** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements.  See the NOTICE file* distributed with this work for additional information* regarding copyright ownership.  The ASF licenses this file* to you under the Apache License, Version 2.0 (the* "License"); you may not use this file except in compliance* with the License.  You may obtain a copy of the License at**  http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on an* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied.  See the License for the* specific language governing permissions and limitations* under the License.*/package org.apache.struts2.views.jsp.ui;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.jsp.JspException;import org.apache.struts2.components.Anchor;import org.apache.struts2.components.Component;import cn.itcast.oa.domain.User;import com.opensymphony.xwork2.util.ValueStack;/*** @see Anchor*/public class AnchorTag extends AbstractClosingTag {private static final long serialVersionUID = -1034616578492431113L;protected String href;protected String includeParams;protected String scheme;protected String action;protected String namespace;protected String method;protected String encode;protected String includeContext;protected String escapeAmp;protected String portletMode;protected String windowState;protected String portletUrlType;protected String anchor;protected String forceAddSchemeHostAndPort;@Overridepublic int doEndTag() throws JspException {// 当前登录用户User user = (User) pageContext.getSession().getAttribute("user");// 当前准备显示的链接对应的权限URL// >> 在开头加上'/'String privUrl = "/" + action;if (user.hasPrivilegeByUrl(privUrl)) {return super.doEndTag(); // 正常的生成并显示超链接 标签,并继续执行页面中后面的代码} else {return EVAL_PAGE; // 不生成与显示超链接 标签,只是继续执行页面中后面的代码}}public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {return new Anchor(stack, req, res);}protected void populateParams() {super.populateParams();Anchor tag = (Anchor) component;tag.setHref(href);tag.setIncludeParams(includeParams);tag.setScheme(scheme);tag.setValue(value);tag.setMethod(method);tag.setNamespace(namespace);tag.setAction(action);tag.setPortletMode(portletMode);tag.setPortletUrlType(portletUrlType);tag.setWindowState(windowState);tag.setAnchor(anchor);if (encode != null) {tag.setEncode(Boolean.valueOf(encode).booleanValue());}if (includeContext != null) {tag.setIncludeContext(Boolean.valueOf(includeContext).booleanValue());}if (escapeAmp != null) {tag.setEscapeAmp(Boolean.valueOf(escapeAmp).booleanValue());}if (forceAddSchemeHostAndPort != null) {tag.setForceAddSchemeHostAndPort(Boolean.valueOf(forceAddSchemeHostAndPort).booleanValue());}}public void setHref(String href) {this.href = href;}public void setEncode(String encode) {this.encode = encode;}public void setIncludeContext(String includeContext) {this.includeContext = includeContext;}public void setEscapeAmp(String escapeAmp) {this.escapeAmp = escapeAmp;}public void setIncludeParams(String name) {includeParams = name;}public void setAction(String action) {this.action = action;}public void setNamespace(String namespace) {this.namespace = namespace;}public void setMethod(String method) {this.method = method;}public void setScheme(String scheme) {this.scheme = scheme;}public void setValue(String value) {this.value = value;}public void setPortletMode(String portletMode) {this.portletMode = portletMode;}public void setPortletUrlType(String portletUrlType) {this.portletUrlType = portletUrlType;}public void setWindowState(String windowState) {this.windowState = windowState;}public void setAnchor(String anchor) {this.anchor = anchor;}public void setForceAddSchemeHostAndPort(String forceAddSchemeHostAndPort) {this.forceAddSchemeHostAndPort = forceAddSchemeHostAndPort;}}

② 拦截用户输入的url,用户可能直接在浏览器栏输入添加的url,这时候也要拦截并判断是否有权限访问,没有的话跳转到无权访问界面。

判断方法就在第二步的CheckPrivilegeInterceptor 拦截器中

    // 如果未登录if (user == null) {if (privUrl.startsWith("/user_login")) { // "/user_loginUI", "/user_login"// 如果是去登录,就放行return invocation.invoke();} else {// 如果不是去登录,就转到登录页面return "loginUI";}}// 如果已登 录,就判断权限else {if (user.hasPrivilegeByUrl(privUrl)) {// 如果有权限,就放行return invocation.invoke();} else {// 如果没有权限,就转到提示页面return "noPrivilegeError";}}

小结

基于URL的权限验证的整个流程大概也就这样了,梳理完感觉清晰很多。不过这种基于URL拦截的方式实现权限认证也太繁琐了,在上面也看到了,需要咱们完成很多工作,不利于项目的维护。不过后面会讲解一种高大上,并且快速简单的权限开发方式Shiro框架,拭目以待。

基于URL的权限验证流程总结相关推荐

  1. WebApi权限验证流程的设计和实现

    前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问,本文通过Form认证,Mvc的Controller基类及Action的权 ...

  2. 从壹开始前后端分离 [ vue + .netcore 补程 ] 三十一║ Nuxt终篇:基于Vuex的权限验证探究...

    缘起 哈喽大家好,今天周四啦,楼主明天要正式放假了,这里先祝大家节日快乐咯,希望在家里能继续研究点儿东西吧,今天呢是 nuxt 的最后一篇,主要是对权限登陆进行研究,这一块咱们之前在说第一个项目的时候 ...

  3. shiro、基于url权限管理、超详细

    如果需要本篇博客内容的代码!请到我的博客下载中心去下载   https://download.csdn.net/download/qq_36125138/10719559 项目运行图: 权限管理原理知 ...

  4. Token及Token验证流程

    什么是Token?为什么要使用它? Token实际就是在计算机身份验证中的令牌(临时)的意思. 当前端向后端发起数据请求的时候,后端需要对前端进行身份验证,但是我们又不想每次都输入用户名和密码,这是就 ...

  5. 基于角色的权限控制模型RBAC

    本文来说下基于角色的权限控制模型RBAC 文章目录 概述 RBAC权限模型简介 RBAC的演化进程 用户与权限直接关联 一个用户拥有一个角色 一个用户一个或多个角色 页面访问权限与操作权限 数据权限 ...

  6. 图文详解基于角色的权限控制模型RBAC

    我们开发一个系统,必然面临权限控制的问题,即不同的用户具有不同的访问.操作.数据权限.形成理论的权限控制模型有:自主访问控制(DAC: Discretionary Access Control).强制 ...

  7. 项目一:第十二天 1、常见权限控制方式 2、基于shiro提供url拦截方式验证权限 3、在realm中授权 5、总结验证权限方式(四种) 6、用户注销7、基于treegrid实现菜单展示...

    1 课程计划 1. 常见权限控制方式 2. 基于shiro提供url拦截方式验证权限 3. 在realm中授权 4. 基于shiro提供注解方式验证权限 5. 总结验证权限方式(四种) 6. 用户注销 ...

  8. shiro教程(1)-基于url权限管理

    一. 权限管理 1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自 ...

  9. 基于 Annotation 拦截的 Spring AOP 权限验证方法

    余 清, 软件工程师, IBM 简介: 使用 Annotation 可以非常方便的根据用户的不同角色,分配访问 Java 方法的权限.在 Java Web 开发中,使用这种方法,可以提高系统的松耦合度 ...

最新文章

  1. 土壤学报:张福锁院士等提出根际生命共同体新概念
  2. [SCOI2005]扫雷
  3. AIOps-一位研发工程师的学习笔记
  4. LeetCode 之 JavaScript 解答第141题 —— 环形链表 I(Linked List Cycle I)
  5. [转]数据库事务ACID特性
  6. c语言数据结构插入算法说明,C语言数据结构插入算法
  7. 一周以来的工作总结--oracle分区的迁移
  8. 微服务 java9模块化_Java9系列第8篇-Module模块化编程
  9. (231)DPU数据处理单元现有产品介绍
  10. 计算机云客户端技术指标,云服务器技术指标
  11. 高级版本 【多后台】
  12. 微信小程序云开发教程-微信小程序的JS基础-事件响应与视图层数据获取
  13. IDEA如何使用SVN插件
  14. 大厂面试为什么总考算法
  15. Arduino 实现PWM输出背后的相关知识
  16. Pandas缺失值inf与nan处理实践
  17. 美化 PowerShell
  18. 全球航天电机行业调研及趋势分析报告
  19. SpringBoot在使用测试的时候是否需要@RunWith?
  20. 数据化建设知识图谱(文末附PDF下载)

热门文章

  1. 2022年起重机械指挥操作证考试题模拟考试平台操作
  2. Qt5详细入门知识介绍
  3. 【月光宝盒get√】用时间置换空间,聊聊稀疏数组的那些事儿
  4. Java后端:分享一些好的Java编码习惯,助你成就大神之路!
  5. 关于sublime代码格式化和关闭更新提示
  6. 本科生以高中学历报考PMP后续会有影响吗?
  7. 人工智能翻译能否取代人工翻译
  8. window 10如何创建虚拟桌面
  9. 64位下Python安装PIL图像处理库 (ERROR: Could not find a version that satisfies the requirement PIL (from vers)
  10. 真实场景超分算法-Real-ESRGAN