Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement JWT based authentication and authorization in Spring Security

How to implement JWT based authentication and authorization in Spring Security

I am trying to implement jwt based authentication and authorization in my spring boot app. I followed a tutorial written here. But it does not do anything in my app. It does not return jwt token rather I am authenticated and my request is fulfilled. I am new to spring security. here is my code.

I want my app return jwt token and using the token the requests must be authorized.

Here is my code.

JWTAuthenticationFilter.java

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    @Autowired
    CustomUserDetailsService userService;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException {

    try {

        CustomUserDetails user = new ObjectMapper().readValue(request.getInputStream(), CustomUserDetails.class);

        return authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
    } catch (Exception e) {
    }

    return super.attemptAuthentication(request, response);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
        Authentication auth) {

    String loggedInUser = ((CustomUserDetails) auth.getPrincipal()).getUsername();

    Claims claims = Jwts.claims().setSubject(loggedInUser);

    if (loggedInUser != null) {
        CustomUserDetails user = (CustomUserDetails) userService.loadUserByUsername(loggedInUser);
        String roles[] = {};

        for (Role role : user.getUser().getUserRoles()) {
        roles[roles.length + 1] = role.getRole();
        }
        claims.put("roles", roles);

        claims.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME));

    }

    String token = Jwts.builder().setClaims(claims)
        .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
        .signWith(SignatureAlgorithm.HS512, SECRET.getBytes()).compact();
    response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);

    }

}

JWTAuthorizationFilter.java

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

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(HEADER_STRING);
    if (header == null || !header.startsWith(TOKEN_PREFIX)) {
        chain.doFilter(request, response);
        return;
    }

    UsernamePasswordAuthenticationToken authentication = getToken(request);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    chain.doFilter(request, response);

    }

    @SuppressWarnings("unchecked")
    private UsernamePasswordAuthenticationToken getToken(HttpServletRequest request) {

    String token = request.getHeader(HEADER_STRING);

    System.out.println("-----------------------------------------------------");
    System.out.println("Token: " + token);
    System.out.println("-----------------------------------------------------");

    if (token != null) {

        Claims claims = Jwts.parser().setSigningKey(SECRET.getBytes())
            .parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
        String user = claims.getSubject();

        ArrayList<String> roles = (ArrayList<String>) claims.get("roles");

        ArrayList<MyGrantedAuthority> rolesList = new ArrayList<>();

        if (roles != null) {
        for (String role : roles) {
            rolesList.add(new MyGrantedAuthority(role));
        }
        }
        if (user != null) {
        return new UsernamePasswordAuthenticationToken(user, null, null);
        }
        return null;
    }
    return null;
    }

}

SecurityConfig.java

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

    @Qualifier("userDetailsService")
    @Autowired
    CustomUserDetailsService userDetailsService;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
    try {
        auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder);

    } catch (Exception e) {

    }

    }

    /*
     * @Autowired public void configureGlobal(AuthenticationManagerBuilder auth)
     * throws Exception {
     * auth.inMemoryAuthentication().withUser("student").password("student").roles(
     * "student").and().withUser("admin") .password("admin").roles("admin"); }
     */

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

    http.csrf().disable();
    // http.authorizeRequests().anyRequest().permitAll();

    // http.authorizeRequests().antMatchers("/api/**").permitAll();

    http.addFilter(new JWTAuthenticationFilter(authenticationManager));
    http.addFilter(new JWTAuthorizationFilter(authenticationManager));

    http.authorizeRequests().antMatchers("/api/student/**").hasAnyRole("STUDENT", "ADMIN");
    http.authorizeRequests().antMatchers("/api/admin/**").hasRole("ADMIN");
    http.authorizeRequests().antMatchers("/api/libararian/**").hasAnyRole("LIBRARIAN", "ADMIN");
    http.authorizeRequests().antMatchers("/api/staff/**").hasAnyRole("STAFF", "ADMIN");
    http.authorizeRequests().antMatchers("/api/teacher/**").hasAnyRole("TEACHER", "ADMIN");
    http.authorizeRequests().antMatchers("/api/parent/**").hasAnyRole("PARENT", "ADMIN");
    http.httpBasic().authenticationEntryPoint(jwtAuthenticationEntryPoint);

    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    // http.formLogin().and().logout().logoutSuccessUrl("/login?logout").permitAll();

    }

}

MyGrantedAuthority.java

    public class MyGrantedAuthority implements GrantedAuthority {

        String authority;

        MyGrantedAuthority(String authority) {
        this.authority = authority;
        }

        @Override
        public String getAuthority() {
        // TODO Auto-generated method stub
        return authority;
        }

    }

JWTAuthenticationEntryPoint.java

@Component
public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
        throws IOException, ServletException {
    response.setStatus(403);
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);

    String message;
    if (exception.getCause() != null) {
        message = exception.getCause().getMessage();
    } else {
        message = exception.getMessage();
    }
    byte[] body = new ObjectMapper().writeValueAsBytes(Collections.singletonMap("error", message));
    response.getOutputStream().write(body);
    }

}
like image 805
Arul Rozario Avatar asked Mar 06 '23 16:03

Arul Rozario


1 Answers

I got it. I followed another tutorial which made my job easy. Here is the complete rewrite working code

TokenProvider.java

package com.cloudsofts.cloudschool.security;

import static com.cloudsofts.cloudschool.security.SecurityConstants.EXPIRATION_TIME;
import static com.cloudsofts.cloudschool.security.SecurityConstants.SECRET;

import java.util.ArrayList;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import com.cloudsofts.cloudschool.people.users.pojos.CustomUserDetails;
import com.cloudsofts.cloudschool.people.users.pojos.Role;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class TokenProvider {

    @Autowired
    CustomUserDetailsService userService;

    public String createToken(String username) {

    CustomUserDetails user = (CustomUserDetails) userService.loadUserByUsername(username);

    Claims claims = Jwts.claims().setSubject(username);

    ArrayList<String> rolesList = new ArrayList<String>();

    for (Role role : user.getUser().getUserRoles()) {
        rolesList.add(role.getRole());

    }

    claims.put("roles", rolesList);

    String token = Jwts.builder().setClaims(claims)
        .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).setIssuedAt(new Date())
        .signWith(SignatureAlgorithm.HS512, SECRET).compact();

    return token;
    }

    public Authentication getAuthentication(String token) {
    String username = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody().getSubject();
    UserDetails userDetails = this.userService.loadUserByUsername(username);

    return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
    }
}

JWTFilter.java

package com.cloudsofts.cloudschool.security;

import static com.cloudsofts.cloudschool.security.SecurityConstants.HEADER_STRING;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;

public class JWTFilter extends GenericFilterBean {

    public final static String AUTHORIZATION_HEADER = "Authorization";

    private final TokenProvider tokenProvider;

    public JWTFilter(TokenProvider tokenProvider) {
    this.tokenProvider = tokenProvider;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
        throws IOException, ServletException {
    try {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        String jwt = resolveToken(httpRequest);
        if (jwt != null) {
        Authentication authentication = this.tokenProvider.getAuthentication(jwt);
        if (authentication != null) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        }

        chain.doFilter(servletRequest, servletResponse);
    } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException
        | UsernameNotFoundException e) {
        // Application.logger.info("Security exception {}", e.getMessage());
        ((HttpServletResponse) servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    }
    }

    private String resolveToken(HttpServletRequest request) {
    String bearerToken = request.getHeader(HEADER_STRING);
    if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
        return bearerToken.substring(7, bearerToken.length());
    }
    return null;
    }

}

JWTConfigurer.java

import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

public class JWTConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    private final TokenProvider tokenProvider;

    public JWTConfigurer(TokenProvider tokenProvider) {
    this.tokenProvider = tokenProvider;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {

    JWTFilter customFilter = new JWTFilter(tokenProvider);
    http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
    }

}

SecurityConfig.java

import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.cloudsofts.cloudschool.people.users.pojos.User;

@RestController
public class LoginController {

    private AuthenticationManager authenticationManager;

    private TokenProvider tokenProvider;

    private CustomUserDetailsService userService;

    LoginController(AuthenticationManager auth, CustomUserDetailsService service, TokenProvider tokenProvider) {
    this.authenticationManager = auth;
    this.userService = service;
    this.tokenProvider = tokenProvider;
    }

    @PostMapping("/login")
    public String getToken(@RequestBody User user, HttpServletResponse response) {

    UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(user.getUsername(),
        user.getPassword());

    authenticationManager.authenticate(authToken);
    return tokenProvider.createToken(user.getUsername());

    }
}

LoginController.java

import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.cloudsofts.cloudschool.people.users.pojos.User;

@RestController
public class LoginController {

    private AuthenticationManager authenticationManager;

    private TokenProvider tokenProvider;

    private CustomUserDetailsService userService;

    LoginController(AuthenticationManager auth, CustomUserDetailsService service, TokenProvider tokenProvider) {
    this.authenticationManager = auth;
    this.userService = service;
    this.tokenProvider = tokenProvider;
    }

    @PostMapping("/login")
    public String getToken(@RequestBody User user, HttpServletResponse response) {

    UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(user.getUsername(),
        user.getPassword());

    authenticationManager.authenticate(authToken);
    return tokenProvider.createToken(user.getUsername());

    }
}

Link to the Github project that helped me.

like image 50
Arul Rozario Avatar answered Mar 09 '23 06:03

Arul Rozario