【发布时间】: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代替hasRole。hasRole将使用角色前缀(默认为ROLE_)并检查用户是否被授予ROLE_VIEWER而不是。hasAuthority不使用这个,所以可以工作。
标签: spring spring-boot spring-security