Spring boot how make a user role managing with jwt

28,173

Solution 1

You need to store user roles inside JWT token as additional claims, extract them after token validation and pass as 'authorities' for principal:

 Collection<? extends GrantedAuthority> authorities
                = Arrays.asList(claims.get(AUTHORITIES_KEY).toString().split(",")).stream()
                .map(authority -> new SimpleGrantedAuthority(authority))
                .collect(Collectors.toList());

        User principal = new User(claims.getSubject(), "",
                authorities);

        UsernamePasswordAuthenticationToken t
                = new UsernamePasswordAuthenticationToken(principal, "", authorities);

Solution 2

First need to add the roles inside the JWT. For that you can add as Claim in the JWT Generator class.

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        Set<String> Userroles = new HashSet<>();
        User user = userRepository.findByUsername(userDetails.getUsername());
        for(Role role:user.getRoles()){
            Userroles.add(role.getName());
        }
        claims.put("Roles",Userroles.toArray());
        return createToken(claims, userDetails.getUsername());
    }

    private String createToken(Map<String, Object> claims, String subject) {
        
        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
    }

In the user model class need to include the roles in Set or any other data structure.

 @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "USER_ROLES", joinColumns = {
            @JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
            @JoinColumn(name = "ROLE_ID") })
    private Set<Role> roles;

In the Repository need to have a method like below.

User findByUsername(String username);

Please check this Github Repo(https://github.com/Senthuran100/SpringBoot_JWT) for your reference.

Solution 3

you should add role into Token and for example you can refer following link:- http://www.svlada.com/jwt-token-authentication-with-spring-boot/

Share:
28,173
Marco Ferraioli
Author by

Marco Ferraioli

Hi, I’m Marco Ferraioli A.K.A. ParanoiaSystem. I’m 23 years old. I’m a student at UNISA (University of Salerno) and study computer science.

Updated on July 05, 2022

Comments

  • Marco Ferraioli
    Marco Ferraioli almost 2 years

    I'm writing a RESTful api with spring boot. I'm using spring boot, jersey, mongo db, swagger, spring boot security and jwt.

    I have written the models, the repositories for the requests to the DB. Now I have integrated the Security and jwt token.

    Now I need to discretize the role of the users, because a user cant call a route that need an admin priviledges.

    I have a route for login, it's return a token. This is the code of my SecurityConfig

    ...
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
        @Autowired
        UserRepository userRepository;
    
        @Override
        public void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.csrf().disable().authorizeRequests()
                    .antMatchers("/").permitAll()
                    .antMatchers("/api/swagger.json").permitAll()
                    .antMatchers(HttpMethod.POST, "/login").permitAll()
                    .antMatchers("/api/*").authenticated()
                    .and()
    
                    .addFilterBefore(new JWTLoginFilter("/login", authenticationManager(), userRepository),
                            UsernamePasswordAuthenticationFilter.class)
    
                    .addFilterBefore(new JWTAuthenticationFilter(),
                            UsernamePasswordAuthenticationFilter.class);
        }
    
    }
    

    I written the JWTLoginFilter that return me the token when user makes login

    ...
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException, IOException, ServletException {
        Credential creds = new ObjectMapper().readValue(req.getInputStream(), Credential.class);
    
        User user = userRepository.login(creds);
    
        if (user == null)
            throw new BadCredentialsException("");
    
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
            creds.getUsername(),
            creds.getPassword()
        );
    
        return token;
    }
    ...
    

    I want insert this on my endpoint class on method

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    

    this is a part of an endpoint

    ....
    
    @Component
    @Path("story")
    @Api(value = "Story", produces = "application/json")
    public class StoryEndpoint {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(StoryEndpoint.class);
    
        @Autowired
        StoryRepository storyRepository;
    
    
        @GET
        @Path("/")
        @Produces(MediaType.APPLICATION_JSON)
        @PreAuthorize("hasRole('ROLE_ADMIN')") <--- I want insert here
        @ApiOperation(value = "Get All Story", response = Story.class)
        @ApiResponses(value = {
                @ApiResponse(code = 200, message = "hello resource found"),
                @ApiResponse(code = 404, message = "Given admin user not found")
        })
        public Response getAllStory(){
            Iterable<Story> stories = storyRepository.findAll();
            LOGGER.info("getAllStory");
            return (stories!=null) ? Response.ok(stories).build() : Response.ok(ResponseErrorGenerator.generate(Response.Status.NOT_FOUND)).status(Response.Status.NOT_FOUND).build();
        }
    ....
    

    How I can make a mechanism for assign to user the role and how i can pass the role in token and discretize on route the role of user?