Spring Boot Jwt 返回访问被拒绝
Posted
技术标签:
【中文标题】Spring Boot Jwt 返回访问被拒绝【英文标题】:Spring Boot Jwt returns access denied 【发布时间】:2020-06-13 14:45:41 【问题描述】:大家好,我对 Java 的 jwt 有疑问。这里是代码。 这是邮递员的返回值
"timestamp": "2020-02-29T20:53:35.761+0000",
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/login"
TokenManager.java
@Service
public class TokenManager
private static final int expiredAt = 10 * 60 * 60 * 1000;
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public String generateToken(String username)
return Jwts.builder().setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiredAt))
.signWith(key).compact();
public boolean tokenValidate(String token)
if(getUserFromToken(token) != null && isExpired(token))
return true;
return false;
public String getUserFromToken(String token)
Claims claims = getClaims(token);
return claims.getSubject();
public boolean isExpired(String token)
Claims claims = getClaims(token);
return claims.getExpiration().after(new Date(System.currentTimeMillis()));
private Claims getClaims(String token)
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
然后是 JwtTokenFilter.java
@Component
public class JwtTokenFilter extends OncePerRequestFilter
@Autowired
private TokenManager tokenManager;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
@NotNull HttpServletResponse httpServletResponse,
@NotNull FilterChain filterChain) throws ServletException, IOException
final String authHeader = httpServletRequest.getHeader("Authorization");
String username = null;
String token = null;
if (authHeader != null && authHeader.contains("Bearer"))
token = authHeader.substring(7);
try
username = tokenManager.getUserFromToken(token);
catch (Exception e)
System.out.println(e.getMessage());
if (username != null && token != null
&& SecurityContextHolder.getContext().getAuthentication() == null)
if (tokenManager.tokenValidate(token))
UsernamePasswordAuthenticationToken upassToken =
new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
upassToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(upassToken);
filterChain.doFilter(httpServletRequest, httpServletResponse);
And my custom UserDetailService
@Service
public class CustomUserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
return userRepository.findByUsername(username);
这里是 WebSecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private JwtTokenFilter tokenFilter;
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable()
.authorizeRequests().antMatchers("/signup","/login").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
@Bean
public AuthenticationManager getAuthenticationManager() throws Exception
return super.authenticationManagerBean();
最后一个是我的控制器。我检查了请求正文并打印了它工作正常但 /login 路径返回访问被拒绝的数据。
@RestController
public class UserController
@Autowired
private UserService userService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenManager tokenManager;
public UserController(UserService userService, AuthenticationManager authenticationManager, TokenManager tokenManager)
this.userService = userService;
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
@RequestMapping(value = "/signup", method = RequestMethod.POST)
public ResponseEntity<User> signup(@RequestBody User user)
return ResponseEntity.ok(userService.save(user));
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<String> login(@Valid @RequestBody AuthRequest authRequest)
try
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(),authRequest.getPassword()));
return ResponseEntity.ok(tokenManager.generateToken(authRequest.getUsername()));
catch (Exception e)
throw e;
当我在登录函数中删除 authenticationManager.authenticate 方法时,它返回一个有效的令牌。但是当我再次添加 authenticationManager 时,它返回访问被拒绝。
【问题讨论】:
【参考方案1】:其实你没有正确设置AuthenticationManager
。
在您的代码中,您只是使用了默认身份验证管理器。没关系,因为 Spring 引导安全中提供了一个默认实现,即ProviderManager
。 [ProviderManager][1]
所做的是:
通过
AuthenticationProviders
列表迭代身份验证请求。
所以你至少需要一个AuthenticationProvider
有不少AuthenticationProviders
,例如:
AnonymousAuthenticationProvider
、NullAuthenticationProvider
、DaoAuthenticationProvider
、LdapAuthenticationProvider
等
在您的情况下,您正在对数据库进行身份验证,因此选择 DaoAuthenticationProvider
。
Spring security 有一种非常简单的方法来配置DaoAuthenticationProvider
,实际上,当您将userDetailsService 设置为AuthenticationManagerBuilder
以配置您的AuthenticationManager
时,它会自动为您创建一个,代码如下:
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService);
所以您需要做的就是将上面的代码片段添加到您的 WebSecurityConfig
并且还建议使用 PasswordEncoder 而不是将密码存储为纯文本。一个简单的方法是在将用户保存到数据库之前使用 BCryptPasswordEncoder 对密码进行编码...
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
【讨论】:
以上是关于Spring Boot Jwt 返回访问被拒绝的主要内容,如果未能解决你的问题,请参考以下文章
用户''@'localhost'的访问被拒绝(使用密码:NO)spring-boot
SQLException:在 Spring Boot 中访问被拒绝
mvn spring-boot:run 导致用户'root'@'localhost'的访问被拒绝(使用密码:YES)
Spring Boot:Oauth2:访问被拒绝(用户是匿名的);重定向到身份验证入口点
Spring Boot + Azure Active Directory 签名的 JWT 被拒绝:需要另一个算法,或者找不到匹配的密钥
从 Spring Boot Starter 1.3.5.RELEASE 升级到 1.5.2 RELEASE 时 Spring Security 中的访问被拒绝错误