提要 本文是 小小商城-SSH 版的 细节详解系列 之一,项目 github:https://github.com/xenv/S-mall-ssh 本文代码大部分在 github 中 可以找到。
有用户系统,就必须有配套的鉴权系统来确保页面不被非法访问。市面上的鉴权系统,最为成熟的就是 shiro,但是体量太重,使用也不太方便,对代码的侵入型也比较强,所以我简单使用 自定义注解 和 Stratus 拦截器 就实现了一个 简单 的鉴权系统,虽然不及 shiiro 稳定和功能强大,但是也足够使用,并且配置非常简单。
具体实现 原理其实非常简单,先在 action 类和 方法上配置好自定义注解,然后配置一个拦截器读取这些注解,在和 session 里面的 user 比对 权限,判断是否放行即可。
在配置自定义注解时,我选择了类和方法同时配置,方法如果不配置则使用类的权限配置。
在 User 实体类中,用 enum 定义用户组
1 2 3 public enum Group{ unLogin,user,admin,superAdmin; }
定义一个自定义注解
1 2 3 4 5 6 @Retention (RetentionPolicy.RUNTIME) @Target ({METHOD,TYPE}) @Inherited public @interface Auth { User.Group value () ; }
在 action 类中加入这个自定义注解
比如前台的 Action 中,可以在 action 类上面加一个 @Auth(User.Group.unLogin) ,这样该 action 类下面的所有方法 unLogin 用户都可以访问。对于不想要 unLogin 用户 访问 的方法,可以在那个方法上面加上 @Auth(User.Group.user) ,就会覆盖掉 类的权限配置。
配置一个拦截器实现鉴权动作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class AuthInterceptor extends AbstractInterceptor { @Override public String intercept (ActionInvocation actionInvocation) throws Exception { Object action =actionInvocation.getAction(); String methodName=actionInvocation.getProxy().getMethod(); Auth authInMethod=action.getClass().getMethod(methodName).getAnnotation(Auth.class ) ; Auth authInClass = action.getClass().getAnnotation(Auth.class ) ; int pageRate = authInClass==null ?0 :authInClass.value().ordinal(); pageRate = authInMethod == null ?pageRate:authInMethod.value().ordinal(); int userRate = 0 ; User user = (User) ActionContext.getContext().getSession().get("user" ); if (user!=null ){ userRate = user.getGroup().ordinal(); } if (pageRate>userRate){ if (userRate == 0 ) { ServletActionContext.getResponse().sendRedirect("/login" ); return null ; } return "/noAuth" ; } return actionInvocation.invoke(); } }
使拦截器生效,在 struts.xml 中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <package name="basic-struts" extends="struts-default" > <interceptors> <interceptor name="authInterceptor" class ="tmall.interceptor.AuthInterceptor" /> <interceptor-stack name="myInterceptors" > <interceptor-ref name="authInterceptor" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <default -interceptor-ref name="myInterceptors" /> <global-results> <result name="/noAuth">/noAuth</result> </global-results> </package>
OK,大功告成。