tags: [小小商城, SSM]
categories: [技术实战]


提要

本文是 小小商城-SSM版的 细节详解系列 之一,项目 github:https://github.com/xenv/S-mall-ssm 本文代码大部分在 github 中 可以找到。

这篇文章其实和 SSH开发 | 配合自定义注解 和 Stratus拦截器,实现 方法级粒度 用户鉴权 大致一样,只是具体实现有一点区别。

有用户系统,就必须有配套的鉴权系统来确保页面不被非法访问。市面上的鉴权系统,最为成熟的就是shiro,但是体量太重,使用也不太方便,对代码的侵入型也比较强,所以我简单使用 自定义注解 和 SpringMVC 拦截器 就实现了一个 简单 的鉴权系统,虽然不及 shiiro 稳定和功能强大,但是也足够使用,并且配置非常简单。

具体实现

原理其实非常简单,我们先在 controller 类和 方法上配置好权限的自定义注解,然后配置一个拦截器读取这些注解,在和 session 里面的 user 比对 权限,判断是否放行即可。

在配置自定义注解时,我选择了类和方法同时配置,方法如果不配置则使用类的权限配置。

1. 在User实体类中,用enum定义用户组

  1. public enum Group{
  2. unLogin,user,admin,superAdmin;
  3. }

2. 定义一个自定义注解

  1. @Retention(RetentionPolicy.RUNTIME) // 运行时可以被获取
  2. @Target({METHOD,TYPE}) //加载类上或者方法上面
  3. @Inherited //可以子类继承
  4. public @interface Auth {
  5. User.Group value(); //User.Group是一个enum类型,在User实体类中定义
  6. }

3. 在 Controller 类中加入这个自定义注解

比如前台的 Controller 中,可以在 这个 controller 类上面加一个 @Auth(User.Group.unLogin) ,这样该 action 类下面的所有方法 unLogin 用户都可以访问。对于不想要 unLogin 用户 访问 的方法,可以在那个方法上面加上 @Auth(User.Group.user) ,就会覆盖掉 类的权限配置。

4.配置一个拦截器实现鉴权动作 AuthInterceptor.java

  1. public class AuthInterceptor extends HandlerInterceptorAdapter {
  2. @Override
  3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
  4. if (!(o instanceof HandlerMethod)) {
  5. return true;
  6. }
  7. HandlerMethod handler = (HandlerMethod) o;
  8. //获取访问页面的权限
  9. //获取方法上的注解
  10. Auth authInMethod = ((HandlerMethod) handler).getMethodAnnotation(Auth.class);
  11. //获取类上的注解
  12. Auth authInClass = ((HandlerMethod) handler).getBean().getClass().getAnnotation(Auth.class);
  13. //获取Enum方法的ordinal,根据大小来确定该页面权限
  14. int pageRate = authInClass == null ? 0 : authInClass.value().ordinal();
  15. pageRate = authInMethod == null ? pageRate : authInMethod.value().ordinal();
  16. //获取用户的权限
  17. int userRate = 0;
  18. User user = (User) request.getSession().getAttribute("user");
  19. if (user != null) {
  20. userRate = user.getGroup().ordinal();
  21. }
  22. //根据权限决定是否放行
  23. if (pageRate > userRate) {
  24. if (userRate == 0) {
  25. response.sendRedirect("/login?refer=/");
  26. return false;
  27. }
  28. throw new AuthException("您已登录,但是没有权限访问这里");
  29. }
  30. return true;
  31. }
  32. }

对于没有权限的用户,可以跳转到登陆页面或者抛出错误即可

5.使拦截器生效,在SpringMVC.xml中配置

  1. <mvc:interceptors>
  2. ....
  3. <bean class="tmall.interceptor.AuthInterceptor"/>
  4. ....
  5. </mvc:interceptors>

  OK,大功告成。