夕辞

spring自定义权限管理,spring实现权限管理拦截器 | 夕辞夕辞

spring自定义权限管理,spring实现权限管理拦截器

开发一个小项目时,针对不同接口要有权限管理的控制,没有动态分配权限那么复杂,主要区分管理员和用户。

于是调研了常用的权限验证框架,主要参考了shiro、spring security、spring OAuth2。

在阅读完这些框架的文档以及尝试搭建后,一点也不想用它们了。

这些框架很成熟,支持缓存、验证各种环节的定制化,但是对于小项目来说,还是有一定理解成本,而且初始化配置起来也挺麻烦的

对于大多数小项目来说,用不着那么多扩展,其实就是想实现一个简单的登录及权限验证,所以我决定自己实现。

 

实现思路很简单,主要以下几个考虑点:

  1. 自定义拦截器,根据URL进行拦截:这点跟框架思路都是一样的,都是基于拦截器实现的;
  2. 使用Cookie存储token进行验签:我非常不喜欢Spring security中JdbcDaoImpl默认的SQL,限制太死了,更倾向于使用客户端无法看出含义的token进行验签;
  3. 缓存及其他扩展:这部分自己写定制化程度更高,比如不想每次都查库,那可以用内存缓存或者Redis也都行,也都不复杂;

 

好了,下面开始搞。

 

第一步:定义一个自定义的LoginInterceptor实现HandlerInterceptor

 

注意,不同版本的spring-mvc表现不同,比如5.x版本的不要求全部实现接口,有默认实现,根据个人项目中版本情况,我们关键要实现preHandle方法,即访问逻辑内容之前的拦截。

拦截器定义代码如下:

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse,
            Object o) throws Exception {
        //这里就是验证操作,稍后在这里写代码
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse,
            Object o,
            ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse,
            Object o,
            Exception e) throws Exception {

    }
}

XML配置如下(也可以使用注解@Bean):

<mvc:interceptor>
    <mvc:mapping path="/manage/**"/>
    <mvc:exclude-mapping path="/login"/>
    <bean class="com.test.interceptor.LoginInterceptor"/>
</mvc:interceptor>

以下是注解的使用方式:

@Configuration
public class MyWebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInteceptor).addPathPatterns("/user/**");
       
    }

    //这里@Bean,是为了能在Interceptor里用@Autowired等注入其他类,也可以直接在LoginInterceptor上面加@Component
    @Bean
    public MpLoginInteceptor loginInteceptor() {
        return new LoginInteceptor();
    }

}

 

第二步:先确定验证方式,我使用Cookie来验证。

 

由于直接依赖session会导致服务器重启后用户需要重新登录,因此在用户登录成功后,我会给用户生成一个token存到库里,保证通过token能查询到登录的是谁。

如果是网页应用,也可以直接把token设置到cookie里,加上生命周期,确保下次打开浏览器后还能记住上次登录状态,代码如下:

Cookie cookie = new Cookie("token", "token值");
cookie.setMaxAge(expire);
cookie.setPath(path);
response.addCookie(cookie);

如果非网页应用,可以使用Cookie,也可以在header里设置token,这个自己定就好,区别只是获取token时的代码不同,比如很多小程序喜欢把token放在header里。

 

第三步:实现preHandler,读取token。

 

读取token有多种方式,根据自己在登陆时的设置,代码如下:

@Override
public boolean preHandle(HttpServletRequest httpServletRequest,
        HttpServletResponse httpServletResponse,
        Object o) throws Exception {
    String token = null;
    //如果是直接放在参数里,比如get或者post的参数里
    token = httpServletRequest.getParameter("token");
    //如果是放在Cookie里,我封装了一个util方法,下面有
    token = getCookieValue(httpServletRequest, "token");
    //如果是放在了Header里,key是可以改的,自己设置什么名字都行,只要保证设置和读取一致
    token = httpServletRequest.getHeader("token");
    //下面就是根据token获取用户信息就可以了
    //token不存在或根据token查不到用户信息,就是违法的
    return false;
}

public static String getCookieValue(HttpServletRequest request, String key) {
    Cookie[] cookies = request.getCookies();
    if (null == cookies) {
        return null;
    }
    for (Cookie cookie : cookies) {
        if (key.equals(cookie.getName())) {
            return cookie.getValue();
        }
    }
    return null;
}

 

以上基本上就是整个框架了,小项目完全没问题了,在此基础上自己还可以扩展。

比如根据token查询用户信息加一个本地缓存,或者自定义一个权限注解,可以做根据角色更精确的权限控制,也都很简单,后续有需要可以再讨论下。

2022年9月15日 / /
标签:  暂无标签
回到顶部