我最近在JWT
应用中将Spring-Security
与Spring-boot
进行了整合。身份验证部分工作正常。但是,基于角色的授权没有按预期工作。
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
public WebSecurityConfig( UserDetailsService userDetailsService )
{
this.userDetailsService = userDetailsService;
}
@Override
protected void configure( HttpSecurity http ) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/rest/user/hello").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter( AuthenticationManager auth )
{
authenticationManager = auth;
}
@Override
public Authentication attemptAuthentication( HttpServletRequest req, HttpServletResponse res )
throws AuthenticationException
{
try
{
UserModel creds = new ObjectMapper().readValue(req.getInputStream(), UserModel.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(creds.getUserName(),
creds.getPassword(), Collections.<GrantedAuthority> emptyList()));
}
catch( IOException e )
{
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication( HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth ) throws IOException, ServletException
{
String role = auth.getAuthorities().iterator().next().toString();
String token = Jwts.builder().claim("role",role).setSubject(((User) auth.getPrincipal()).getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 3600000000l))
.signWith(SignatureAlgorithm.HS256, Constant.SECRET).compact();
res.addHeader(Constant.HEADER_STRING, Constant.TOKEN_PREFIX + token);
res.setStatus(HttpServletResponse.SC_OK);
String tokenJsonResponse = new ObjectMapper().writeValueAsString("Ok");
res.addHeader("Content-Type", "application/json");
res.getWriter().print(tokenJsonResponse);
}
}
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter( AuthenticationManager authManager )
{
super(authManager);
}
@Override
protected void doFilterInternal( HttpServletRequest req, HttpServletResponse res, FilterChain chain )
throws IOException, ServletException
{
String header = req.getHeader(Constant.HEADER_STRING);
if( header == null || !header.startsWith(Constant.TOKEN_PREFIX) )
{
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication( HttpServletRequest request )
{
String token = request.getHeader(Constant.HEADER_STRING);
if( token != null )
{
// parse the token.
String user = Jwts.parser().setSigningKey(Constant.SECRET)
.parseClaimsJws(token.replace(Constant.TOKEN_PREFIX, "")).getBody().getSubject();
if( user != null )
{
return new UsernamePasswordAuthenticationToken(user, null, Collections.<GrantedAuthority> emptyList());
}
return null;
}
return null;
}
}
如果我在登录应用程序时进行调试,则会在权限中显示Authentication
role=ADMIN
但是,如果我向/rest/user/hello
发送请求,则在登录后,即使登录用户具有ADMIN角色,它也会抛出消息Access Denied
的异常。如何解决这个问题?