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

Spring boot 使用JWT在spring安全性中基于角色的访问,spring-boot,spring-security,jwt,spring-security-oauth2,Spring Boot,Spring Security,Jwt,Spring Security Oauth2,我最近在Spring boot应用程序中集成了JWT和Spring Security。身份验证部分工作正常。但是,基于角色的授权并没有像预期的那样发挥作用 @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; public WebSecurityConfi

我最近在
Spring boot
应用程序中集成了
JWT
Spring Security
。身份验证部分工作正常。但是,基于角色的授权并没有像预期的那样发挥作用

@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;
}
}
@EnableWebSecurity
公共类WebSecurityConfig扩展了WebSecurityConfigureAdapter{
@自动连线
私有用户详细信息服务用户详细信息服务;
公共网站安全配置(UserDetailsService UserDetailsService)
{
this.userDetailsService=userDetailsService;
}
@凌驾
受保护的无效配置(HttpSecurity http)引发异常
{
http.csrf().disable()
.授权请求()
.antMatchers(“/login”).permitAll()
.antMatchers(“/rest/user/hello”).hasRole(“ADMIN”)
.anyRequest().authenticated()
.及()
.addFilter(新的JWTAuthenticationFilter(authenticationManager()))
.addFilter(新的JWTAuthorizationFilter(authenticationManager());
http.sessionManagement().sessionCreationPolicy(sessionCreationPolicy.STATELESS);
}
}
公共类JWTAuthenticationFilter扩展了UsernamePasswordAuthenticationFilter{
私人AuthenticationManager AuthenticationManager;
公共JWTAuthenticationFilter(AuthenticationManager身份验证)
{
authenticationManager=auth;
}
@凌驾
公共身份验证尝试身份验证(HttpServletRequest-req、HttpServletResponse-res)
抛出AuthenticationException
{
尝试
{
UserModel creds=new ObjectMapper().readValue(req.getInputStream(),UserModel.class);
返回authenticationManager.authenticate(新用户名PasswordAuthenticationToken(creds.getUserName(),
creds.getPassword(),Collections.emptyList());
}
捕获(IOE异常)
{
抛出新的运行时异常(e);
}
}
@凌驾
受保护的无效成功身份验证(HttpServletRequest-req、HttpServletResponse-res、FilterChain-chain、,
身份验证(auth)引发IOException、ServletException
{
字符串角色=auth.getAuthories().iterator().next().toString();
String token=Jwts.builder().claim(“角色”,role).setSubject(((用户)auth.getPrincipal()).getUsername())
.setExpiration(新日期(System.currentTimeMillis()+3600000000l))
.signWith(SignatureAlgorithm.HS256,常量.SECRET).compact();
res.addHeader(常量.HEADER\u字符串,常量.TOKEN\u前缀+令牌);
res.setStatus(HttpServletResponse.SC_OK);
字符串tokenJsonResponse=newObjectMapper().writeValueAsString(“确定”);
res.addHeader(“内容类型”、“应用程序/json”);
res.getWriter().print(tokenJsonResponse);
}
}
公共类JWTAuthorizationFilter扩展了基本身份验证筛选器{
公共JWTAuthorizationFilter(AuthenticationManager authManager)
{
超级经理;
}
@凌驾
受保护的无效doFilterInternal(HttpServletRequest请求、HttpServletResponse请求、FilterChain链)
抛出IOException、ServletException
{
字符串头=req.getHeader(常量头\u字符串);
if(header==null | |!header.startsWith(Constant.TOKEN|前缀))
{
链式过滤器(要求、恢复);
返回;
}
UsernamePasswordAuthenticationTokenAuthentication=getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(身份验证);
链式过滤器(要求、恢复);
}
私有用户名PasswordAuthenticationToken getAuthentication(HttpServletRequest请求)
{
字符串标记=request.getHeader(常量.HEADER\u字符串);
if(令牌!=null)
{
//解析令牌。
String user=Jwts.parser().setSigningKey(Constant.SECRET)
.parseClaimsJws(token.replace(Constant.token_前缀“”)).getBody().getSubject();
如果(用户!=null)
{
返回新的UsernamePasswordAuthenticationToken(user,null,Collections.emptyList());
}
返回null;
}
返回null;
}
}
如果我在登录应用程序时进行调试,则会显示身份验证在权限中具有
role=ADMIN


但在登录后,如果我向
/rest/user/hello
发送请求,则会引发异常,并显示消息
访问被拒绝
,即使登录的用户具有管理员角色。如何解决此问题?

您需要将其用作“antMatchers”(/admin”)。访问(“hasRole('admin')和hasRole('DBA')”``请参见此处。在上面的链接中,它仍然有
.antMatchers(“/admin/**”).hasRole(“admin”)
而没有
访问权限。任何以“/admin/”开头的URL将仅限于具有“role\u admin”角色的用户。