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