文章地址:http://www.haha174.top/article/details/258083
項目源碼:https://github.com/haha174/jwt-token.git
具體的實際效果能夠看考這裏 目前已經部署一個 我的測試機器上面:
http://cloud.codeguoj.cn/api-cloud-server/swagger-ui.html#!/token45controller/loginUsingPOST
相信不少人都調用過api, 通常的大體基本步驟都是先用登錄得到一個token,而後使用token調用api 或者直接給你一個token 憑藉token調用api.
那麼這裏實現一個spring security+ redis+ jwt 發token 和驗證token的一個項目。
首先須要安裝redis 若是不會的小夥伴能夠參考http://www.haha174.top/article/details/257478 這篇博客。
建立一個maven項目導入依賴css
<?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>
編寫 token 攔截器 經過重寫springsecurity AbstractAuthenticationProcessingFilterhtml
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); } }
自定義校驗java
@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); } }
配置spring security 將上述的攔截器配置到spring security 的攔截器鏈上 和攔截規則git
@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; } }
生成token 使用json web toekngithub
public class JavaWebToken { private static Logger log = LoggerFactory.getLogger(JavaWebToken.class); //該方法使用HS256算法和Secret:bankgl生成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; } //使用HS256簽名算法和生成的signingKey最終的Token,claims中是有效載荷 public static String createJavaWebToken(Map<String, Object> claims) { return Jwts.builder() .setIssuer("Jersey-Security-Basic")//設置發行人 .setSubject("subject")//設置抽象主題 .setAudience("login")//設置角色 .setExpiration(getDate())//過時時間 .setIssuedAt(new Date())//設置如今時間 .setClaims(claims) .signWith( SignatureAlgorithm.HS256,getKeyInstance()) .compact(); } //解析Token,同時也能驗證Token,當驗證失敗返回null 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; } } }
配置swagger
在請求頭中加入headerweb
@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>()); }
整合redis 能夠參考這篇博客
http://www.haha174.top/article/details/251216
只須要啓動應用 訪問http://localhost:8080/swagger-ui.html#/
----
redis