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

2018-11-17 13:09:43 +08:00
 src112159

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

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

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

这个是有配置了的。
src112159
2018-11-17 14:59:29 +08:00
也有没有权限的返回值 json。 但就是不知道它为啥还会跳转到登录页
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
2018-11-17 15:14:12 +08:00
@src112159
你的意思是你在数据库配置了用户-资源权限表,然后要这个表决策是吧。可以实现 AuthenticationProvider 注入 grands,然后用`accessDecisionManager`决策。
但其实这和手动写个 filter 差不多。
beny2mor
2018-11-17 15:19:42 +08:00
我好像理解错你的意思了?

你的登录页是指 security 的那个丑表单吗?
你是不是开启了 httpBasic
src112159
2018-11-17 15:29:26 +08:00
是跳转到了自定义的登录页。我现在就是在数据库配置了用户-资源权限表,用表里的资源来控制的
src112159
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
2018-11-17 15:52:50 +08:00
@beny2mor 这样权限控制好像是没有问题的,但就是会跳转到自定义的登录页面
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
2018-11-17 16:15:16 +08:00
![插入图片]( https://files.catbox.moe/4nve3e.jpg)

你没有设置 authenticationProvider 或 AccessDecisionManager,那么 authenticationEntryPoint 和 accessDeniedHandler 也不会生效。 你的代码好像就只有你有 filter 生效,并没有用到 security 的 Authentication 机制....
src112159
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
2018-11-17 16:44:57 +08:00
@beny2mor

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

是完全没进入 AccessDecisionManager 吗。不过 AccessDecisionManager 好像需要先 setAuthenticated(true);才会进入。
beny2mor
2018-11-17 16:49:15 +08:00
@src112159 #15 啥, 哪里 logout 了
beny2mor
2018-11-17 17:00:11 +08:00
@beny2mor 好吧,前端退出。。。
security 也可以写测试的吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/508752

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX