使用JWT在Spring安全性中基于角色的访问

时间:2017-11-17 11:13:06

标签: spring-boot spring-security jwt spring-security-oauth2

我最近在JWT应用中将Spring-SecuritySpring-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;
}
}

如果我在登录应用程序时进行调试,则会在权限enter image description here中显示Authentication role=ADMIN

但是,如果我向/rest/user/hello发送请求,则在登录后,即使登录用户具有ADMIN角色,它也会抛出消息Access Denied的异常。如何解决这个问题?

0 个答案:

没有答案