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?
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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With