【问题标题】:Spring Security: user with role is not able to access to endpointSpring Security:具有角色的用户无法访问端点
【发布时间】:2020-07-19 10:24:48
【问题描述】:

我创建了这个简单的控制器:

@RestController
@RequestMapping("/orders")
public class OrderController {

    @GetMapping("/list")
    @PreAuthorize(value = "hasRole('VIEWER')")
    public List<String> list() {
        return new ArrayList<String>();
    }

}

如您所见,它受到@PreAuthorize(value = "hasRole('VIEWER')") 的保护。

根据日志:

Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@99305100: Principal: username; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: VIEWER
Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter@4799314a, returned: -1
Voter: org.springframework.security.access.vote.RoleVoter@41e7ad2c, returned: 0
Voter: org.springframework.security.access.vote.AuthenticatedVoter@79a89d7d, returned: 0
Access is denied (user is not anonymous); delegating to AccessDeniedHandler

org.springframework.security.access.AccessDeniedException: Access is denied

如您所见,用户已通过身份验证并具有角色VIEWER。但是,由于"access is denied",它无法到达_/orders/list 端点。

以前的日志sn-p:

校长:用户名;凭证:[受保护];已认证:真实;详细信息:空;授予权限:查看者

我的JWTFilter 看起来像:

package com.tsystems.covid.marketplace.backend.config.security;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

public class JWTAuthorizationFilter extends OncePerRequestFilter {

    private static final Logger LOG = LoggerFactory.getLogger(JWTAuthorizationFilter.class);

    private TokenProperties tokenProperties;

    public JWTAuthorizationFilter(
        TokenProperties tokenProperties
    ) {
        this.tokenProperties = tokenProperties;
    }

    @Override
    protected void doFilterInternal(
        HttpServletRequest request,
        HttpServletResponse response,
        FilterChain filterChain
    ) throws ServletException, IOException {

        Claims claims = this.getAuthorizationToken(request)
            .map(this::validateToken)
            .orElse(null);

        if (null != claims) {
            this.setUpAuthentication(claims);
        }

        filterChain.doFilter(request, response);
    }

    /**
     * 
     * @param request
     * @return
     */
    private Optional<String> getAuthorizationToken(HttpServletRequest request) {
        return Optional
            .ofNullable(request.getHeader(SecurityConstants.AUTHORIZATION_HEADER))
            .filter(header -> header.startsWith(SecurityConstants.TOKEN_PREFIX))
            .map(header -> header.replace(SecurityConstants.TOKEN_PREFIX, ""));
    }

    /**
     * 
     * @param token
     * @return
     */
    private Claims validateToken(String token) {
        return Jwts.parser()
            .setSigningKey(this.tokenProperties.getSecret())
            .parseClaimsJws(token)
            .getBody();
    }

    /**
     * 
     * @param claims
     */
    private void setUpAuthentication(Claims claims) {
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
            claims.getSubject(),
            null,
            this.parseAuthorities((List<String>)claims.get(SecurityConstants.JWT_AUTHORITIES_CLAIM))
        );

        SecurityContextHolder.getContext().setAuthentication(auth);
    }

    /**
     * 
     * @param authorities
     * @return
     */
    private List<GrantedAuthority> parseAuthorities(List<String> authorities) {
        return authorities
            .stream()
            .map(SimpleGrantedAuthority::new)
            .collect(Collectors.toList());
    }

}

有什么想法吗?

【问题讨论】:

  • 使用hasAuthority 代替hasRolehasRole 将使用角色前缀(默认为ROLE_)并检查用户是否被授予ROLE_VIEWER 而不是。 hasAuthority 不使用这个,所以可以工作。

标签: spring spring-boot spring-security


【解决方案1】:

我认为这是因为spring的默认前缀 试着做这个

@RestController
@RequestMapping("/orders")
public class OrderController {

    @GetMapping("/list")
    @PreAuthorize(value = "hasRole('ROLE_VIEWER')")
    public List<String> list() {
        return new ArrayList<String>();
    }

}

因为spring默认在角色前添加ROLE_

【讨论】:

    【解决方案2】:

    你给Granted Authorities: VIEWER然后你需要使用hasAuthority

    @PreAuthorize(value = "hasAuthority('VIEWER')")
    

    如果你想使用hasRole 然后传递Granted Authorities: ROLE_VIEWER 那么你可以使用这个:

    @PreAuthorize(value = "hasRole('VIEWER')")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-25
      • 2013-12-08
      • 2017-10-19
      • 2012-12-27
      • 1970-01-01
      • 2017-10-31
      • 2019-08-08
      相关资源
      最近更新 更多