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”角色的用户。