当我尝试使用POSTMAN调用受保护的ws,并在登录Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJBZGVsSVAiLCJpYXQiOjE1NTI2MDM4NTIsImV4cCI6MTU1MjY5MDI1Mn0.OfzkQlhubdLBa9cV7O231M1AB8ya9g5Q1zefhjhPvJIICz45SUunT2xP6r008O-oxUXBQT3RrRha7n6gSo9Jpw
后传递带有获得的令牌的Authorization标头时,出现以下错误。
例外:
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:379)
org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:223)
org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
com.spring.jwtauthentication.controller.TestRestAPIs$$EnhancerBySpringCGLIB$$11db1a81.adminAccess(<generated>)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
请在我的实现下方找到:
1)登录api AuthRestAPIs.java:
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
public class AuthRestAPIs {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
private UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
PasswordEncoder encoder;
@Autowired
JwtProvider jwtProvider;
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser( @RequestBody LoginForm loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginRequest.getUsername(),
loginRequest.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtProvider.generateJwtToken(authentication);
return ResponseEntity.ok(new JwtResponse(jwt));
}
}
测试api apiTestRestAPIs.java(受保护的资源):
@RestController
public class TestRestAPIs {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/api/test//admin")
public String adminAccess() {
return ">>> Admin Contents";
}
}
2)安全配置类
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = "com.spring.jwtauthentication", scopedProxy = ScopedProxyMode.INTERFACES)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
@Autowired
private JwtAuthEntryPoint unauthorizedHandler;
public JwtAuthTokenFilter authenticationJwtTokenFilter() {
JwtAuthTokenFilter test = new JwtAuthTokenFilter();
return test;
}
@Autowired
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().
authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
3)JwtAuthTokenFilter.java:
@Component
public class JwtAuthTokenFilter extends OncePerRequestFilter {
@Autowired
private JwtProvider tokenProvider;
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(JwtAuthTokenFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = getJwt(request);
if (jwt!=null && tokenProvider.validateJwtToken(jwt)) {
String username = tokenProvider.getUserNameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication
= new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Can NOT set user authentication -> Message: {}", e);
}
filterChain.doFilter(request, response);
}
private String getJwt(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
return authHeader.replace("Bearer ","");
}
return null;
}
}
4)JwtProvider.java
@Component
public class JwtProvider {
private static final Logger logger = LoggerFactory.getLogger(JwtProvider.class);
private String jwtSecret = "jwtOlfaSecretKey";
private int jwtExpiration =86400;
public String generateJwtToken(Authentication authentication) {
UserPrinciple userPrincipal = (UserPrinciple) authentication.getPrincipal();
return Jwts.builder()
.setSubject((userPrincipal.getUsername()))
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpiration*1000))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public boolean validateJwtToken(String authToken) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
return true;
} catch (SignatureException e) {
logger.error("Invalid JWT signature -> Message: {} ", e);
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token -> Message: {}", e);
} catch (ExpiredJwtException e) {
logger.error("Expired JWT token -> Message: {}", e);
} catch (UnsupportedJwtException e) {
logger.error("Unsupported JWT token -> Message: {}", e);
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty -> Message: {}", e);
}
return false;
}
public String getUserNameFromJwtToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody().getSubject();
}
}
5)JwtAuthEntryPoint.java:
@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(JwtAuthEntryPoint.class);
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e)
throws IOException, ServletException {
logger.error("Unauthorized error. Message - {}", e.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error -> Unauthorized");
}
}
6)web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>myApp</display-name>
<servlet>
<servlet-name>myApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/cfg.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
7)pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
答案 0 :(得分:1)
使用@PreAuthorize(“ hasAuthority('ADMIN')”)而不是@PreAuthorize(“ hasRole('ADMIN')”),这样就可以解决您的问题。