Redis JWT Spring Boot Spring security implements API token validation

Source: Internet
Author: User
Tags auth getmessage install redis



Article Address: http://www.haha174.top/article/details/258083
Project Source: Https://github.com/haha174/jwt-token.git
Specific practical effects can be seen here at present a personal test machine has been deployed above:
Http://cloud.codeguoj.cn/api-cloud-server/swagger-ui.html#!/token45controller/loginUsingPOST
Believe that many people have called the API, the general basic step is to first use the login to obtain a token, and then use token call API or directly to you a token with token call API.
Then here's a project that implements a spring security+ redis+ JWT token and validates tokens.
First you need to install Redis if not the small partners can refer to http://www.haha174.top/article/details/257478 this blog.
Create a Maven project import dependency


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wen.security</groupId>
    <artifactId>jwt-token</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    </properties>
    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-parent</artifactId>
           <version>1.5.6.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.44</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>

    </dependencies>
</project>


Write token interceptors by overriding springsecurity Abstractauthenticationprocessingfilter


public class AuthTokenFilter extends AbstractAuthenticationProcessingFilter
{
  Logger logger = LoggerFactory.getLogger(this.getClass());

  @Value("${token.header}")
  private String tokenHeader;
  
  @Value("${token.name}")
  private String tokenName;
  
  public AuthTokenFilter(RequestMatcher matcher)
  {
    super(matcher);
  }
  
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
      throws AuthenticationException, IOException, ServletException
  {
    String authToken = request.getHeader(this.tokenHeader);
    if(StringUtils.isEmpty(authToken))
    {
      authToken = request.getParameter(this.tokenName);
    }
    logger.debug("start to check token:{} *************");
    if (authToken == null)
    {
      throw new AuthenticationCredentialsNotFoundException("Access Token is not provided");
    }
    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(authToken, null);
    return getAuthenticationManager().authenticate(authentication);
    
  }
  
  @Override
  protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
      Authentication auth) throws IOException, ServletException
  {
    SecurityContext context = SecurityContextHolder.createEmptyContext();
    context.setAuthentication(auth);
    SecurityContextHolder.setContext(context);
    chain.doFilter(request, response);
  }

  @Override
  protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException authException) throws IOException, ServletException
  {
    SecurityContextHolder.clearContext();
    response.setStatus(HttpStatus.UNAUTHORIZED.value());
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    String message;
    if (authException.getCause() != null)
    {
      message = authException.getCause().getMessage();
    }
    else
    {
      message = authException.getMessage();
    }

    BaseResponse baseResponse = new BaseResponse();
    baseResponse.setStatusCode(IConstants.RESPONSE_STATUS_CODE_FAILED);
    baseResponse.setStatusMsg(message);

    byte[] body = new ObjectMapper().writeValueAsBytes(baseResponse);
    response.getOutputStream().write(body);
  }
}


Custom Validation


@Component
public class AuthTokenProvider implements AuthenticationProvider
{
  Logger logger = LoggerFactory.getLogger(this.getClass());

  @Autowired
  protected HttpServletRequest request;

  @Autowired
  TokenService tokenService;
  
  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException
  {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if(auth!=null && auth.isAuthenticated())
    {
      return new UsernamePasswordAuthenticationToken(auth.getPrincipal(), null, new ArrayList<>());
    }
    String token = (String) authentication.getPrincipal();
    if (token != null)
    {
      if (!tokenService.checkToken(token))
      {
        throw new CredentialsExpiredException("Access Token is expired. Please login again.");
      }
    }
    else
    {
      throw new BadCredentialsException("Invalid token String.");
    }
    logger.debug("Authenticated successfully.");
    return new UsernamePasswordAuthenticationToken(token, null, new ArrayList<>());
  }
  
  @Override
  public boolean supports(Class<?> authentication)
  {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }

}


Configure spring Security to configure the above interceptors on the spring security interceptor chain and interception rules


@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebAuthConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Bean
    public AuthTokenFilter authenticationTokenFilterBean() throws Exception {
        List<String> pathsToSkip = Arrays.asList("/login");
        List<String> processingPath = Arrays.asList("/service/**","/logout");
        SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, processingPath);
        AuthTokenFilter filter = new AuthTokenFilter(matcher);
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers("/", "/*.html", "/**/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                .and().addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
        httpSecurity.cors().configurationSource(corsConfigurationSource());
        httpSecurity.logout().disable();
        httpSecurity.headers().cacheControl();

    }
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        return filter;
    }
}


Generate tokens using JSON web TOEKN


public class JavaWebToken {

    private static Logger log = LoggerFactory.getLogger (JavaWebToken.class);

    // This method uses HS256 algorithm and Secret: bankgl to generate signKey
    private static Key getKeyInstance () {
        // We will sign our JavaWebToken with our ApiKey secret
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        byte [] apiKeySecretBytes = DatatypeConverter.parseBase64Binary ("token");
        Key signingKey = new SecretKeySpec (apiKeySecretBytes, signatureAlgorithm.getJcaName ());
        return signingKey;
    }

    // Using the HS256 signature algorithm and the generated signingKey final token, the payload is in the claims
    public static String createJavaWebToken (Map <String, Object> claims) {
        return Jwts.builder ()
                .setIssuer ("Jersey-Security-Basic") // Set publisher
                .setSubject ("subject") // Set abstract subject
                .setAudience ("login") // Set role
                .setExpiration (getDate ()) // Expiration time
                .setIssuedAt (new Date ()) // Set the current time
                .setClaims (claims)
                .signWith (SignatureAlgorithm.HS256, getKeyInstance ())
                .compact ();
    }

    // Parse the token and verify the token at the same time, and return null when the verification fails
    public static Map <String, Object> parserJavaWebToken (String jwt) {
        try {
            Map <String, Object> jwtClaims =
                    Jwts.parser (). SetSigningKey (getKeyInstance ()). ParseClaimsJws (jwt) .getBody ();
            return jwtClaims;
        } catch (Exception e) {
            log.error ("json web token verify failed");
            return null;
        }
    }
    public static Date getDate () {
        try {
        / * SimpleDateFormat format = new SimpleDateFormat ("yyyy-MM-dd HH: mm: ss");
            Date date = format.parse (new Date (). GetTime () + new TokenProperties (). GetExpires () * 1000+ "");
            return date; * /
            long currentTime = System.currentTimeMillis ();
            currentTime + = 30 * 60 * 1000 * 2;
            Date date = new Date (currentTime);
            return date;
        } catch (Exception e) {
            e.printStackTrace ();
            long currentTime = System.currentTimeMillis ();
            currentTime + = 30 * 60 * 1000 * 2;
            Date date = new Date (currentTime);
            return date;
        }
    }
}


Configure swagger
to include the header in the request header


@Bean
    public Docket demoApi() {
        ParameterBuilder aParameterBuilder = new ParameterBuilder();
        aParameterBuilder.name("Authorization").description("input the token for authentication either in the authorization field or in the token field").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        ParameterBuilder aParameterBuilder1 = new ParameterBuilder();
        aParameterBuilder1.name("token").description("input the token for authentication either in the authorization field or in the token field").modelRef(new ModelRef("string")).parameterType("query").required(false).build();
        List<Parameter> aParameters = new ArrayList<Parameter>();
        aParameters.add(aParameterBuilder.build());
        aParameters.add(aParameterBuilder1.build());
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo()).useDefaultResponseMessages(false).globalOperationParameters(aParameters)
                .select()  .apis(RequestHandlerSelectors.basePackage("com.wen.token.web")).build();
    }
    protected ApiInfo getApiInfo()
    {
      return new ApiInfo("Rest Web Service", "total api  Rest Web Service " + new Date(), "", "",
          new Contact("cxhc", "", ""), "", "",new ArrayList<VendorExtension>());
    }


The integration of Redis can refer to this blog
http://www.haha174.top/article/details/251216
Only need to launch app access http://localhost:8080/swagger-ui.html#/

----



Redis JWT Spring Boot Spring security implements API token validation


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.