Search code examples
spring-bootspring-securityspring-security-rest

Unable to implement Role based access to Spring-Boot API


I am new to Spring-Boot.I want to create an API which will have role based access with JWT token based authentication. But, unable to implement that.

I am not using JPA & Hibernate to fetch and map data. Instead I am using Ibatis.I have tried with @PreAuthorize and antMatchers & hasRole, but failed. By getting user id from JWT token, I am fetching details and roles and setting those to SecurityContextHolder.getContext().setAuthentication, still not working.

SecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .csrf().disable()

   .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
          .and()
          .addFilter(new JwtAuthorizationFilter(authenticationManager()))
          .authorizeRequests()
          .anyRequest().authenticated()
          .antMatchers("api/management/reports").hasRole("Supervisor");
    }

Controller

@RestController
@RequestMapping("api")
@CrossOrigin
public class MyController {

    @PreAuthorize("hasRole('Supervisor')")
    @GetMapping("username")
    public String reports(){
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return securityContext.getAuthentication().getName();
    }
}

AuthorizationFilter

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

String header = request.getHeader(JwtProperties.HEADER_STRING);
if (header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }

        Authentication authentication = getUsernamePasswordAuthentication(request,header);
        SecurityContextHolder.getContext().setAuthentication(authentication);


        chain.doFilter(request, response);
}
private Authentication getUsernamePasswordAuthentication(HttpServletRequest request, String header) {
        try {
String token = header.replace(JwtProperties.TOKEN_PREFIX,"");
String userName = JWT.require(HMAC512(JwtProperties.SECRET.getBytes()))
                        .build()
                        .verify(token)
                        .getSubject();
List<User> searchedUserList = getUserDetailsDAO().getUserDetails(userName);


    if (null !=searchedUserList && searchedUserList.size()>0) {

        User searchedUser = new User();
        searchedUser = searchedUserList.get(0);
        List<RoleAccess> roleAccessList = new ArrayList<RoleAccess>();
    XrefUsrRole oXrefUsrRole = new XrefUsrRole();
    oXrefUsrRole.setUserName(searchedUser.getUsername());
    roleAccessList = getRoleAccessDAO().getAccessDetails(oXrefUsrRole);
    List<GrantedAuthority> authorities = uildUserAuthority(roleAccessList);

    org.springframework.security.core.userdetails.User newUser = buildUserForAuthentication(searchedUser, authorities);

UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(newUser, null,authorities);
                    return auth;
                }
                return null;
            }
            return null;
        } catch (IOException e) {
            return null;
        }

private org.springframework.security.core.userdetails.User buildUserForAuthentication(User searchedUser, List<GrantedAuthority> authorities) {
        return new org.springframework.security.core.userdetails.User(searchedUser.getUsername(), searchedUser.getPassword(), true, true, true, true, authorities);
    }

    private List<GrantedAuthority> buildUserAuthority(List<RoleAccess> roleAccessList) {
        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        // Build user's authorities
        for (RoleAccess userRole : roleAccessList) {
            setAuths.add(new SimpleGrantedAuthority("ROLE_"+userRole.getModifiedBy()));
        }

        List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

        return Result;
    }

In this case api/username should not accessible except users having Supervisor role.


Solution

  • You have ROLE_"+userRole.getModifiedBy()) which means you are granting roles with ROLE_NAME and in PreAuthorize you have Supervisor which is causing the issue. You can store role as ROLE_SUPERVISOR in a database then use it as below

        // Build user's authorities
        for (RoleAccess userRole : roleAccessList) {
            setAuths.add(new SimpleGrantedAuthority("ROLE_"+userRole.getModifiedBy()));
        }
    

    use

    @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
    .antMatchers("api/management/reports").hasRole("SUPERVISOR");