要做一款权限架构,就要适用几个流行的相关框加,struts2是我们公司首先需要考虑的,考虑到侵入性,决定通过切面的方式,在每个Action前进行权限验证,基本思路是:

1,自定义通用权限注解

2,开发抽象切面,预留传入uid的接口

3,配置struts切面,做权限拦截

以下源码是对上边功能的实现:

1,权限注解

/*** 自定义权限注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authority {/*** 权限码* @return*/String authorityCode();}

2,sturts抽象切面

public abstract class ELInterceptor implements Interceptor {private IVerificationUser verificationUser;private ILogicUserAreaFranchiseeService logicUserAreaFranchiseeService;private Result result = new Result(true);@Overridepublic void destroy() {// TODO Auto-generated method stub}protected final Log log = LogFactory.getLog(this.getClass());@Overridepublic void init() {}/*** 拦截类并作权限验证* @param invocation* @return* @throws Exception*/@Overridepublic String intercept(ActionInvocation invocation) throws Exception {log.info("=intercept=>Authority Intercept");// TODO Auto-generated method stubString methodName = invocation.getProxy().getMethod();Method currentMethod = invocation.getAction().getClass().getMethod(methodName);Method[] methods = invocation.getAction().getClass().getMethods();initAuthCode(methods);String isTest = (String) ServletActionContext.getRequest().getParameter("authistest");//如果该方法请求是需要进行验证的时候执行以下逻辑if (currentMethod.isAnnotationPresent(Authority.class)) {//取得权限验证的注解Authority authority = currentMethod.getAnnotation(Authority.class);log.info("=intercept=> get authorityCode");//取得当前请求的注解的authorityCodeString authorityCode = authority.authorityCode();/* ** 然后可以在此判断当前用户是否拥有对应的权限,如果没有可以跳到指定的无权限提示页面,如果拥有则可以* 继续往下执行。**/boolean ispass =false;ispass = Boolean.parseBoolean(getFromVm(authorityCode));if (ispass){if(isTest==null ||isTest.trim().isEmpty()){return invocation.invoke();}else{return "hasauth";}} else {log.info("=intercept=> user not have  this authorityCode");writeJson("<html auth='NOAUTH'></html>");return "noauth";}}log.info("<=intercept=>Authority Intercept");if(isTest==null ||isTest.trim().isEmpty()){return invocation.invoke();}else{return "hasauth";}}private Boolean checkOnline(AuthCheckDomain authCheckDomain){boolean isPass = false;AuthorityUser authorityUser =null;PublicResult<Boolean> publicResult =verificationUser.hasAuth(authCheckDomain);if(publicResult!=null&&publicResult.isSuccess()){isPass = publicResult.getResult();if(publicResult.getAuthorityUser()!=null ){authorityUser=publicResult.getAuthorityUser();authorityUser.setCreated(new Date());AuthCache.authMap.put(authCheckDomain.getAuthCode().trim(),authorityUser);}}return isPass;}private void writeJson(String json){try {HttpServletResponse response = ServletActionContext.getResponse();response.setHeader("contentType", "application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");response.setDateHeader("Expires", 0L);response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-cache");ServletOutputStream out = response.getOutputStream();out.write(json.getBytes("UTF-8"));out.flush();}catch (Exception e){e.printStackTrace();}}private void initAuthCode(Method[] methods){for(Method currentMethod :methods){//如果该方法请求是需要进行验证的时候执行以下逻辑if (currentMethod.isAnnotationPresent(Authority.class)) {//取得权限验证的注解Authority authority = currentMethod.getAnnotation(Authority.class);log.info("=intercept=> get authorityCode");//取得当前请求的注解的authorityCodeString authorityCode = authority.authorityCode();isAuthPass(authorityCode);}}toVm(result);}private boolean  isAuthPass(String authorityCode){log.info("=isAuthPass=>");AuthCheckDomain authCheckDomain = new AuthCheckDomain();Long uid=getUid();String ip=getIP();UserAreaFranchisee userArea =  getUserArea(uid);Long provinceId=null;Long cityId=null;Long townId=null;if(userArea!=null){provinceId=Long.valueOf(userArea.getProvinceid());cityId=Long.valueOf(userArea.getCityid());townId=Long.valueOf(userArea.getCountyid());}authCheckDomain.setAuthCode(authorityCode);authCheckDomain.setUid(uid);authCheckDomain.setIp(ip);authCheckDomain.setProvinceId(provinceId);authCheckDomain.setCityId(cityId);authCheckDomain.setTownId(townId);boolean ispass = false;AuthorityUser authorityUser =null;if(AuthCache.authMap!=null && AuthCache.authMap.containsKey(authorityCode) && AuthCache.authMap.get(authorityCode)!=null ){authorityUser = AuthCache.authMap.get(authorityCode);int nowLong = DateUtil.getCurrentTime();long checkTime = nowLong-(authorityUser.getCreated().getTime()/1000);if(checkTime> RedisIntValueUtils.MapExpireSeconds.getIntValue()){ispass = checkOnline(authCheckDomain);}ispass=CheckAuth.hasAuth(authorityUser,authCheckDomain);}else{ispass=checkOnline(authCheckDomain);}toVmAuthPass(authorityCode, ispass);return ispass;}private void toVmAuthPass(String authCode,boolean isPass){result.addDefaultModel(authCode,isPass);}private void toVm(Result result){ValueStack context = ActionContext.getContext().getValueStack();Set set = result.keySet();Iterator resultCode = set.iterator();context.set("textProvider", this);context.set("datePickerLocale", this.getDatePickerLocale());String text;while(resultCode.hasNext()) {text = (String)resultCode.next();context.set(text, result.get(text));}}private String getFromVm(String authCode){ValueStack context = ActionContext.getContext().getValueStack();Map map = (Map)context.peek();String result = ((Boolean)map.get(authCode)).toString();return result;}private String getDatePickerLocale() {String locale = this.getLocale().toString().toLowerCase();String[] arr = locale.split("_");if(arr[0].equals("en")) {locale = arr[0];} else {locale = arr[0] + "-" + arr[1];}return locale;}public Locale getLocale() {ActionContext ctx = ActionContext.getContext();if(ctx != null) {return ctx.getLocale();} else {return null;}}private UserAreaFranchisee getUserArea(Long uid){UserAreaFranchisee userAreaFranchisee = null;String userJson = RedisUtils.get(RedisKeyUtils.Redis_Key_UserArea.getKeyStr()+uid,String.class);if(userJson==null || userJson.trim().isEmpty()){userAreaFranchisee =  getUserAreaByDubbo(uid);try {if (userAreaFranchisee != null) {RedisUtils.set(RedisKeyUtils.Redis_Key_UserArea.getKeyStr() + uid, JSON.toJSONString(userAreaFranchisee), RedisIntValueUtils.Redis_ExpireSeconds_UserArea.getIntValue());}}catch (Exception e){log.error("=getUserArea=>set reids error",e);}}else{try {userAreaFranchisee = JSON.parseObject(userJson, UserAreaFranchisee.class);}catch(Exception e){log.error("=getUserArea=> json error",e);userAreaFranchisee=null;}}return userAreaFranchisee;}private UserAreaFranchisee getUserAreaByDubbo(Long uid){com.el.common.result.PublicResult<UserAreaFranchisee> result =null;try {result = logicUserAreaFranchiseeService.getUserAreaFranchisee(uid.intValue());}catch (Exception e){log.error("==>error" ,e);result=null;}if(result==null || !result.isSuccess() || result.getResult()==null){return null;}else{return result.getResult();}}private Long getProvinceId(Long uid) {return null;}public Long getCityId(Long uid) {return null;}public Long getTownId(Long uid) {return null;}public abstract Long getUid();public abstract String getIP();public IVerificationUser getVerificationUser() {return verificationUser;}public void setVerificationUser(IVerificationUser verificationUser) {this.verificationUser = verificationUser;}public ILogicUserAreaFranchiseeService getLogicUserAreaFranchiseeService() {return logicUserAreaFranchiseeService;}public void setLogicUserAreaFranchiseeService(ILogicUserAreaFranchiseeService logicUserAreaFranchiseeService) {this.logicUserAreaFranchiseeService = logicUserAreaFranchiseeService;}
}

此处预留了两个抽象方法,依赖具体客户端实现,分别是获取用户id和获取ip

public abstract Long getUid();
    public abstract String getIP();

具体切面(抽象类实现)

@Service
public  class ELInterceptorImpl extends  ELInterceptor {@Autowiredprivate IVerificationUser verificationUser;@Autowiredprivate ILogicUserAreaFranchiseeService logicUserAreaFranchiseeService;public  Long getUid(){String suid = (String) ServletActionContext.getRequest().getSession().getAttribute("uid");Long uid=Long.valueOf((suid==null || suid.isEmpty())?"0":suid);return uid;}@Overridepublic String getIP() {//这里可以从session里面取得当前的用户String suip = (String) ServletActionContext.getRequest().getSession().getAttribute("ip");return suip;}
}

注意:struts切面抽象类中,两个具体的业务服务不能使用spring自动注入,因为spring是扫描包下的类,有注解的维护一个单例的存在,而抽象类不能实例化,所以会报错,我们可以在具体实现类中,注入两个属性,结果是一样的。

3,struts配置

<interceptors><interceptor name="authIntercept" class="com.el.authority.service.intercept.ELInterceptorImpl"/><interceptor-stack name="strutsDefaultStack"><interceptor-ref name="exception"/><interceptor-ref name="alias"/><interceptor-ref name="servletConfig"/><interceptor-ref name="i18n"/><interceptor-ref name="prepare"/><interceptor-ref name="chain"/><interceptor-ref name="debugging"/><interceptor-ref name="scopedModelDriven"/><interceptor-ref name="modelDriven"/><interceptor-ref name="fileUpload"><param name="maximumSize">4194304</param><!--单个文件最大4M --><param name="allowedTypes">image/x-png,image/png,image/gif,image/jpeg,image/jpg,image/pjpeg,text/plain,application/octet-stream</param><param name="allowedExtensions">jpg,jpeg,png,gif,txt,vm</param></interceptor-ref><interceptor-ref name="checkbox"/><interceptor-ref name="multiselect"/><interceptor-ref name="staticParams"/><interceptor-ref name="actionMappingParams"/><interceptor-ref name="params"><param name="excludeParams">dojo\..*,^struts\..*,.*\\u0023.*</param></interceptor-ref><interceptor-ref name="conversionError"/><interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="workflow"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="authIntercept"/></interceptor-stack><interceptor-stack name="taskInterceptor"><interceptor-ref name="strutsDefaultStack"/></interceptor-stack></interceptors><default-interceptor-ref name="taskInterceptor"/><global-results><result name="exception">/WEB-INF/vm/error.vm</result><result name="error">/WEB-INF/vm/error.vm</result><result name="input">/WEB-INF/vm/convertError.vm</result><result name="noauth">/WEB-INF/vm/noauthority.vm</result><result name="hasauth">/WEB-INF/vm/hasauth.vm</result></global-results>

4,struts图示

下图是struts架构的实现,对应到刚刚的配置文件中,我们就能很容易分辨出切面的切入位置

总结:

struts切面的实现,网上有很多例子,大家不防多多参考,本文中的例子主要是给大家交代清楚整体结构,通过这些后台代码及配置,我们就能全局对用户权限控制,进行控制,但是还是有些细节,篇幅所限,大家参考后续的文章,其中会介绍ValueStack的使用,前台控件的自动显隐等。

权限管理框架实现(1)--Struts切面处理相关推荐

  1. shiro 单点登录_Shiro权限管理框架(一):Shiro的基本使用

    其实关于Shiro的一些学习笔记很早就该写了,因为懒癌和拖延症晚期一直没有落实,直到今天公司的一个项目碰到了在集群环境的单点登录频繁掉线的问题,为了解决这个问题,Shiro相关的文档和教程没少翻.最后 ...

  2. shiro 同时实现url和按钮的拦截_Shiro权限管理框架(一):Shiro的基本使用

    其实关于Shiro的一些学习笔记很早就该写了,因为懒癌和拖延症晚期一直没有落实,直到今天公司的一个项目碰到了在集群环境的单点登录频繁掉线的问题,为了解决这个问题,Shiro相关的文档和教程没少翻.最后 ...

  3. 基本权限管理框架,开通淘宝支付

    一直都想做一个后台权限管理框架,不需要太复杂的功能,满足一般需求即可,体积小巧,速度快,基本权限管理框架,就是这样的一个小型权限框架,至于你相不相信我不知道,反正我信!~~ 好吧,先上图,有图才有真像 ...

  4. AppBoxPro - 细粒度通用权限管理框架(可控制表格行内按钮)源码提供下载

    2019独角兽企业重金招聘Python工程师标准>>> 特别声明: 提供的源代码已经包含了 AppBoxPro 的全部源代码,用 VS2012 打开项目后,直接 Ctrl+F5 可以 ...

  5. 基于Spring+SpringMVC+Beetl的权限管理框架源码分享

    Java企业级开发平台源码 权限管理框架源码 源码分享! 基于Spring+SpringMVC+Beetl+Beetlsql+Shiro的权限管理框架.内置功能:用户管理.角色管理.菜单管理.字典管理 ...

  6. Shiro权限管理框架详解

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

  7. Java shiro权限管理框架视频教程

    shiro权限管理框架视频教程 中级 共14课 权限系统在任何一个系统中都存在,随着分布式系统的大行其道,权限系统也趋向服务化,对于一个高级工程师来说,权限系统的设计是必不可少需要掌握的技术栈. 课程 ...

  8. java web权限框架_Java Web通用用户权限管理框架设计与实现

    2014年第 3期 计 算 机 与 现 代 化 JISUANJI YU XIANDAIHUA 总第 223期 文章编号 :1006-2475(2014)03-0177-03 Java Web通用用户权 ...

  9. SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解

    1.预置演示环境 这个演示环境继续沿用 SpringSecurit权限管理框架系列(五)-Spring Security框架自定义配置类详解(一)之formLogin配置详解的环境. 2.自定义配置类 ...

最新文章

  1. ICLR 2019论文解读:量化神经网络
  2. golang中的并发服务器
  3. 前端学习(2995):vue+element今日头条管理--代码测试规范
  4. java 栈和队列实现迷宫代码_使用两个队列实现一个栈
  5. Homebrew 更换阿里云镜像源
  6. Mapbox词汇表中文文档(查找Mapbox相关的术语及其定义)
  7. js返回上级页面的方法(亲测)
  8. java实验报告_java实验一实验报告
  9. MySQL 聚簇索引和非聚簇索引 mysql 索引为啥用b 树
  10. 接口测试平台代码实现15:基于生态考虑的菜单重构+意见反馈功能设计
  11. 基于GIS和Python的百度地图街景爬取
  12. 设置iPhone来电铃声(图文教程)
  13. 亚马逊违反受限商品政策三次,亚马逊恢复受限asin
  14. Improved Pre-Warping for Wide Angle, Head Mounted Displays
  15. 如何在macOS 中让Gatekeeper在任何地方允许应用程序
  16. 老司机 iOS 周报 #41 | 2018-10-29
  17. 【ENSP模拟器】路由基础(HCNP)——A与B互ping的问题
  18. p2psearcher无法连接到KAD网络或ed2k服务器的解决办法
  19. MPG(MPEG2 Program Stream)格式解析
  20. DBeaver 32位 下载安装

热门文章

  1. ciscn_2019_n_4
  2. 《Java黑皮书基础篇第10版》 第3章【习题】
  3. 对计算机财务管理的理解,计算机财务管理.doc
  4. 工作经验分享:Spark调优【优化后性能提升1200%】
  5. 工具类 - 思维导图
  6. Honeywell RTU2020使用.软件篇
  7. oppo手机设置wifi代理和charles证书
  8. Android调用系统分享和指定app分享-微信朋友圈图文分享和qq分享
  9. XDM-跨文档消息传送
  10. python中forward(200)什么意思_Python中的Phyllotaxis模式| 算法植物学的一个单位