V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
src112159
V2EX  ›  Java

用 springSecurity 登录状态下点击无权限的 URL 按钮直接跳转到登录页?

  •  
  •   src112159 · 2018-11-17 13:09:43 +08:00 · 3187 次点击
    这是一个创建于 1980 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个问题不知道咋解。想让用户在点击这个无权限的按钮时候提示他没有权限;我现在是在资源表配置 URL 的方式控制权限的。 万能的 V 友有了解 springSecurity 的吗。万分感谢额

    src112159
        1
    src112159  
    OP
       2018-11-17 13:59:47 +08:00
    我在这个 URL 对应的方法上面加注解 @PreAuthorize("hasRole('ROLE_CO')") ,就能实现不跳转。直接返回 json
    beny2mor
        2
    beny2mor  
       2018-11-17 14:19:12 +08:00
    http.exceptionHandling()
    .authenticationEntryPoint
    .accessDeniedHandler
    src112159
        3
    src112159  
    OP
       2018-11-17 14:54:36 +08:00
    @beny2mor httpSecurity
    .csrf().disable()

    .exceptionHandling()
    .authenticationEntryPoint(unauthorizedHandler)
    .accessDeniedHandler(myAccessDeniedHandler)

    这个是有配置了的。
    src112159
        4
    src112159  
    OP
       2018-11-17 14:59:29 +08:00
    也有没有权限的返回值 json。 但就是不知道它为啥还会跳转到登录页
    johnniang
        5
    johnniang  
       2018-11-17 15:04:44 +08:00
    ```

    @Override
    public void configure(HttpSecurity http) throws Exception {
    http //
    .apply(validateCodeSecurityConfig) //
    .and() //
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //

    .and() //
    .formLogin().permitAll() //
    .loginProcessingUrl("/api/v1/auth/login") //
    .successHandler(authenticationSuccessHandler) //
    .failureHandler(authenticationFailureHandler) //

    ```
    beny2mor
        6
    beny2mor  
       2018-11-17 15:14:12 +08:00
    @src112159
    你的意思是你在数据库配置了用户-资源权限表,然后要这个表决策是吧。可以实现 AuthenticationProvider 注入 grands,然后用`accessDecisionManager`决策。
    但其实这和手动写个 filter 差不多。
    beny2mor
        7
    beny2mor  
       2018-11-17 15:19:42 +08:00
    我好像理解错你的意思了?

    你的登录页是指 security 的那个丑表单吗?
    你是不是开启了 httpBasic
    src112159
        8
    src112159  
    OP
       2018-11-17 15:29:26 +08:00
    是跳转到了自定义的登录页。我现在就是在数据库配置了用户-资源权限表,用表里的资源来控制的
    src112159
        9
    src112159  
    OP
       2018-11-17 15:33:03 +08:00
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
    // 由于使用的是 JWT,我们这里不需要 csrf
    .csrf().disable()

    .exceptionHandling()
    .accessDeniedHandler(myAccessDeniedHandler)
    .authenticationEntryPoint(unauthorizedHandler)
    .and()

    // 基于 token,所以不需要 session
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

    .authorizeRequests()

    // 允许对于网站静态资源的无授权访问
    .antMatchers(
    HttpMethod.GET,
    "/",
    "/*.html",
    "/favicon.ico",
    "/**/*.html",
    "/**/*.css",
    "/**/*.js",
    "/**/*.png",
    "/**/*.jpg"
    ).permitAll()
    // 对于获取 token 的 rest api 要允许匿名访问
    .antMatchers("/api/auth/**").permitAll()
    .antMatchers("/sys_user/**").permitAll()
    .antMatchers("/x_mgr/**/*.*").permitAll()
    // 除上面外的所有请求全部需要鉴权认证
    .anyRequest().authenticated();

    // 添加 JWT filter
    httpSecurity
    .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
    httpSecurity.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
    // 禁用缓存
    httpSecurity.headers().cacheControl();
    }
    src112159
        10
    src112159  
    OP
       2018-11-17 15:52:50 +08:00
    @beny2mor 这样权限控制好像是没有问题的,但就是会跳转到自定义的登录页面
    beny2mor
        11
    beny2mor  
       2018-11-17 16:13:00 +08:00
    @src112159

    你是没进入`myAccessDeniedHandler`而是进入了`unauthorizedHandler`吗。。

    我对 security 的理解是这样的:

    用户认证失败会进入 authenticationEntryPoint 用户认证失败指是的账号、密码对不上,或者 token 找不到用户之类的; 然后这一步是在`authenticationProvider`配置中发生的,如果配置的 AuthenticationProvider 返回 null 就是认证失败,返回 AbstractAuthenticationToken 则是通过。

    用户没有权限会进入 accessDeniedHandler, 用户没权限是指能从 token 或账号密码找到用户,但是没有通过权限认证,比如#1 的 @PreAuthorize("hasRole('ROLE_CO')")注解; 这一步是在 accessDecisionManager 配置的,这里可能是一组 Voter。

    filter 失败会进入会在 filter 中直接写错误的返回(`res.setStatus(403)`之类的)。

    https://files.catbox.moe/4nve3e.jpg
    先后顺序是: 先进入 filter,filter 的作用是设置简单的 Authentication ; 然后进入 authenticationProvider,这一步是判断用户是否合法,并补全 Authentication 信息;最后进入 AccessDecisionManager,这一步会根据补全的 Authentication 判断是否有权限。

    ————

    我是看了一大堆的文章自己理解的,领导让我用 security,但他自己也没怎么用过。。运行起来效果和我想的一样。。
    beny2mor
        12
    beny2mor  
       2018-11-17 16:15:16 +08:00
    ![插入图片]( https://files.catbox.moe/4nve3e.jpg)

    你没有设置 authenticationProvider 或 AccessDecisionManager,那么 authenticationEntryPoint 和 accessDeniedHandler 也不会生效。 你的代码好像就只有你有 filter 生效,并没有用到 security 的 Authentication 机制....
    src112159
        13
    src112159  
    OP
       2018-11-17 16:36:10 +08:00
    @beny2mor
    @Service
    public class MyAccessDecisionManager implements AccessDecisionManager {


    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
    if(null == configAttributes || configAttributes.size() <= 0) {
    return;
    }
    ConfigAttribute c;
    String needRole;
    for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
    c = iter.next();
    needRole = c.getAttribute();
    for(GrantedAuthority ga : authentication.getAuthorities()) {
    if(needRole.trim().equals(ga.getAuthority())) {
    return;
    }
    }
    }
    throw new AccessDeniedException("没有操作权限");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
    return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
    return true;
    }
    }


    ----------------------------------------------------------------


    @Component
    public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
    //返回 json 形式的错误信息
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json");
    response.getWriter().println("{\"code\":1001, \"msg\":\""+e.getMessage()+"\"}");
    response.getWriter().flush();
    }
    }


    ----------------------------------------------------------
    是有 AccessDecisionManager 的,无权限的资源也返回了这个 json,现在就是会自己跳转到登录
    src112159
        14
    src112159  
    OP
       2018-11-17 16:44:57 +08:00
    @beny2mor

    已经找到问题了,谢谢你的帮助哈,。
    src112159
        15
    src112159  
    OP
       2018-11-17 16:46:12 +08:00
    就是因为那个返回的 code 的原因,返回 1001 前段直接 logout 了。。。。
    beny2mor
        16
    beny2mor  
       2018-11-17 16:48:12 +08:00
    不知道惹。。

    是完全没进入 AccessDecisionManager 吗。不过 AccessDecisionManager 好像需要先 setAuthenticated(true);才会进入。
    beny2mor
        17
    beny2mor  
       2018-11-17 16:49:15 +08:00
    @src112159 #15 啥, 哪里 logout 了
    beny2mor
        18
    beny2mor  
       2018-11-17 17:00:11 +08:00
    @beny2mor 好吧,前端退出。。。
    security 也可以写测试的吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2520 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 981ms · UTC 00:18 · PVG 08:18 · LAX 17:18 · JFK 20:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.