From 0f2747b8f3e946c0f79caedde42b5610e18c070b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=88=98=E6=B4=AA=E9=9D=92?= Date: Wed, 11 Sep 2019 22:09:06 +0800 Subject: [PATCH] =?utf8?q?chore:=20=E5=BC=82=E5=B8=B8infras=E7=A4=BA?= =?utf8?q?=E4=BE=8B=E4=BB=A3=E7=A0=81=EF=BC=8C=E9=87=87=E7=94=A8jar?= =?utf8?q?=E5=8C=85=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../security/api/InfrasApiUserController.java | 55 ---- .../JwtAuthenticationToken.java | 74 ----- .../security/core/userdetails/InfrasUser.java | 49 ---- ...frasSecurityReactiveAutoConfiguration.java | 66 ----- .../BasicWebFluxSecurityConfiguration.java | 38 --- .../basic/EnableInfrasBasicWebFluxApi.java | 17 -- .../jwt/EnableInfrasJWTWebFluxApi.java | 17 -- .../reactive/jwt/JWTKeyController.java | 25 -- .../jwt/JWTSecurityContextRepository.java | 118 -------- .../reactive/jwt/JWTTokenController.java | 232 ---------------- .../reactive/jwt/JWTWebFluxConfiguration.java | 141 ---------- .../security/reactive/jwt/LoginRequest.java | 13 - .../infras/security/utils/JWTTokenUtil.java | 261 ------------------ .../main/resources/META-INF/spring.factories | 3 - 14 files changed, 1109 deletions(-) delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/api/InfrasApiUserController.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/authentication/JwtAuthenticationToken.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/core/userdetails/InfrasUser.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/InfrasSecurityReactiveAutoConfiguration.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/BasicWebFluxSecurityConfiguration.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/EnableInfrasBasicWebFluxApi.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/EnableInfrasJWTWebFluxApi.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTKeyController.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTSecurityContextRepository.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTTokenController.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTWebFluxConfiguration.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/LoginRequest.java delete mode 100644 gateway/src/main/java/com/supwisdom/infras/security/utils/JWTTokenUtil.java delete mode 100644 gateway/src/main/resources/META-INF/spring.factories diff --git a/gateway/src/main/java/com/supwisdom/infras/security/api/InfrasApiUserController.java b/gateway/src/main/java/com/supwisdom/infras/security/api/InfrasApiUserController.java deleted file mode 100644 index 26eea40..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/api/InfrasApiUserController.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.supwisdom.infras.security.api; - -import java.security.Principal; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.MediaType; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.userdetails.User; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import com.supwisdom.infras.security.authentication.JwtAuthenticationToken; -import com.supwisdom.infras.security.core.userdetails.InfrasUser; - -@RestController -@RequestMapping("/api/user") -public class InfrasApiUserController { - - private static final Logger logger = LoggerFactory.getLogger(InfrasApiUserController.class); - - @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - @ResponseBody - public InfrasUser current(Principal principal) { - - logger.debug("ApiUserController.current(Principal) is {}", principal); - - if (principal == null) { - throw new RuntimeException("exception.principal.is.null"); - } - - if (principal instanceof UsernamePasswordAuthenticationToken) { - - UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) principal; - - if (token.isAuthenticated()) { - if (token.getPrincipal() instanceof User) { - return (InfrasUser) token.getPrincipal(); - } - } - } else if (principal instanceof JwtAuthenticationToken) { - JwtAuthenticationToken token = (JwtAuthenticationToken) principal; - - InfrasUser user = new InfrasUser((String) token.getPrincipal(), (String) token.getToken(), token.getAuthorities(), token.getAttributes()); - user.eraseCredentials(); - - return user; - } - - throw new RuntimeException("exception.principal.not.correct"); - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/authentication/JwtAuthenticationToken.java b/gateway/src/main/java/com/supwisdom/infras/security/authentication/JwtAuthenticationToken.java deleted file mode 100644 index 73a1944..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/authentication/JwtAuthenticationToken.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.supwisdom.infras.security.authentication; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; - -public class JwtAuthenticationToken extends AbstractAuthenticationToken { - - /** - * - */ - private static final long serialVersionUID = 4407107653933017523L; - - private Object principal; - private String credentials; - private String token; - - private final Map attributes; - - public Map getAttributes() { - return this.attributes; - } - - public JwtAuthenticationToken(String token) { - super(Collections.emptyList()); - this.token = token; - - this.attributes = Collections.emptyMap(); - - setAuthenticated(false); - } - - public JwtAuthenticationToken(Object principal, String token, - Collection authorities) { - this(principal, token, authorities, Collections.emptyMap()); - } - - public JwtAuthenticationToken(Object principal, String token, - Collection authorities, - Map attributes) { - super(authorities); - this.principal = principal; - this.token = token; - - this.attributes = Collections.unmodifiableMap(attributes); - - setAuthenticated(true); - } - - @Override - public void setDetails(Object details) { - super.setDetails(details); - - this.setAuthenticated(true); - } - - @Override - public Object getCredentials() { - return credentials; - } - - @Override - public Object getPrincipal() { - return principal; - } - - public String getToken() { - return token; - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/core/userdetails/InfrasUser.java b/gateway/src/main/java/com/supwisdom/infras/security/core/userdetails/InfrasUser.java deleted file mode 100644 index 8764974..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/core/userdetails/InfrasUser.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.supwisdom.infras.security.core.userdetails; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; - -public class InfrasUser extends User { - - /** - * - */ - private static final long serialVersionUID = 6535845256804630918L; - - public InfrasUser(String username, String password, - Collection authorities, - Map attributes) { - this(username, password, true, true, true, true, authorities, attributes); - - } - - public InfrasUser(String username, String password, - boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, - Collection authorities, - Map attributes) { - super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); - - this.attributes = Collections.unmodifiableMap(attributes); - } - - private final Map attributes; - public Map getAttributes() { - return this.attributes; - } - - public List getRoles() { - List roles = new ArrayList<>(); - for (GrantedAuthority grantedAuthority : this.getAuthorities()) { - roles.add(grantedAuthority.getAuthority()); - } - - return roles; - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/InfrasSecurityReactiveAutoConfiguration.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/InfrasSecurityReactiveAutoConfiguration.java deleted file mode 100644 index 1ea28f4..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/InfrasSecurityReactiveAutoConfiguration.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.supwisdom.infras.security.reactive; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.ReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.User.UserBuilder; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.server.WebFilterChainProxy; - -import com.supwisdom.infras.security.api.InfrasApiUserController; - -import reactor.core.publisher.Flux; - -@Configuration -@ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, WebFilterChainProxy.class }) -public class InfrasSecurityReactiveAutoConfiguration { - - private static final Logger logger = LoggerFactory.getLogger(InfrasSecurityReactiveAutoConfiguration.class); - - @Bean - @ConditionalOnMissingBean({PasswordEncoder.class}) - public PasswordEncoder passwordEncoder() { - - PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); - logger.debug("InfrasSecurityReactiveAutoConfiguration passwordEncoder is {}", passwordEncoder); - - return passwordEncoder; - } - - @Bean - @ConditionalOnMissingBean({ReactiveUserDetailsService.class}) - public MapReactiveUserDetailsService reactiveUserDetailsService() { - - // ensure the passwords are encoded properly - @SuppressWarnings("deprecation") - UserBuilder users = User.withDefaultPasswordEncoder(); - - MapReactiveUserDetailsService reactiveUserDetailsService = new MapReactiveUserDetailsService( - users.username("user").password("password").roles("USER").build(), - users.username("admin").password("password").roles("USER","ADMIN").build() - ); - logger.debug("InfrasSecurityReactiveAutoConfiguration reactiveUserDetailsService is {}", reactiveUserDetailsService); - - return reactiveUserDetailsService; - } - - - - @Bean - @ConditionalOnMissingBean(InfrasApiUserController.class) - public InfrasApiUserController infrasApiUserController() { - InfrasApiUserController infrasApiUserController = new InfrasApiUserController(); - logger.debug("InfrasSecurityReactiveAutoConfiguration infrasApiUserController is {}", infrasApiUserController); - - return infrasApiUserController; - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/BasicWebFluxSecurityConfiguration.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/BasicWebFluxSecurityConfiguration.java deleted file mode 100644 index 76cc927..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/BasicWebFluxSecurityConfiguration.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.supwisdom.infras.security.reactive.basic; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.web.server.SecurityWebFiltersOrder; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; - -@Configuration -@ConditionalOnProperty(name="infras.security.basic.reactive.enabled", havingValue="true") -public class BasicWebFluxSecurityConfiguration { - - @Bean - public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http - .securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/**")) - .authorizeExchange() - .pathMatchers(HttpMethod.OPTIONS).permitAll() - .pathMatchers("/api/public/**", "/api/open/**").permitAll() - .pathMatchers("/api/v*/public/**", "/api/v*/open/**").permitAll() - .pathMatchers("/api/*/v*/public/**", "/api/*/v*/open/**").permitAll() - .pathMatchers("/api/**").authenticated() - .anyExchange().authenticated(); - - //http.addFilterAt(webFilter, SecurityWebFiltersOrder.LAST); - - http.httpBasic(); - http.formLogin().disable(); - - http.csrf().disable(); - - return http.build(); - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/EnableInfrasBasicWebFluxApi.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/EnableInfrasBasicWebFluxApi.java deleted file mode 100644 index 9658d27..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/basic/EnableInfrasBasicWebFluxApi.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.supwisdom.infras.security.reactive.basic; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Import; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Import(BasicWebFluxSecurityConfiguration.class) -public @interface EnableInfrasBasicWebFluxApi { - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/EnableInfrasJWTWebFluxApi.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/EnableInfrasJWTWebFluxApi.java deleted file mode 100644 index 51062b2..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/EnableInfrasJWTWebFluxApi.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.supwisdom.infras.security.reactive.jwt; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Import; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Import(JWTWebFluxConfiguration.class) -public @interface EnableInfrasJWTWebFluxApi { - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTKeyController.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTKeyController.java deleted file mode 100644 index 3c4b036..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTKeyController.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.supwisdom.infras.security.reactive.jwt; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.supwisdom.infras.security.utils.JWTTokenUtil; - -@RestController -public class JWTKeyController { - - @Autowired - private JWTTokenUtil jwtTokenUtil; - - /** - * curl -i -s -X GET 'http://localhost:8080/jwt/publicKey' - * @return - */ - @GetMapping(value = "/jwt/publicKey") - public String publicKey() { - - return jwtTokenUtil.getPublicKeyPem(); - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTSecurityContextRepository.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTSecurityContextRepository.java deleted file mode 100644 index bf2f6a7..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTSecurityContextRepository.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.supwisdom.infras.security.reactive.jwt; - -import io.jsonwebtoken.Claims; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.web.server.context.ServerSecurityContextRepository; -import org.springframework.web.server.ServerWebExchange; - -import com.supwisdom.infras.security.authentication.JwtAuthenticationToken; -import com.supwisdom.infras.security.utils.JWTTokenUtil; - -import reactor.core.publisher.Mono; - -public class JWTSecurityContextRepository implements ServerSecurityContextRepository { - - private static final Logger logger = LoggerFactory.getLogger(JWTSecurityContextRepository.class); - - @Value("${infras.security.jwt.token.authorization.prefix:Bearer}") - private String authorizationPrefix; - - private JWTTokenUtil jwtTokenUtil; - - @Autowired - public JWTSecurityContextRepository(JWTTokenUtil jwtTokenUtil) { - this.jwtTokenUtil = jwtTokenUtil; - } - - @Override - public Mono save(ServerWebExchange exchange, SecurityContext context) { - return Mono.empty(); - } - - @Override - public Mono load(ServerWebExchange exchange) { - - ServerHttpRequest request = exchange.getRequest(); - - String authToken = null; - - String authParamter = request.getQueryParams().getFirst("token"); logger.debug("authParamter is [{}]", authParamter); - if (authParamter != null && !authParamter.isEmpty()) { - authToken = authParamter; - } - - if (authToken == null) { - String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION); logger.debug("authHeader is [{}]", authHeader); - if (authHeader != null && authHeader.toLowerCase().startsWith(authorizationPrefix.toLowerCase())) { - authToken = authHeader.substring(authorizationPrefix.length() + 1); - } - } - - logger.debug("authToken is [{}]", authToken); - - if (authToken != null && !authToken.isEmpty()) { - - String username = getUsernameFromToken(authToken); - - if (username != null) { - List authorities = getAuthoritiesFromToken(authToken); - - Authentication authentication = new JwtAuthenticationToken(username, authToken, authorities); - - return Mono.justOrEmpty(new SecurityContextImpl(authentication)); - } - - } - - return Mono.empty(); - } - - - /** - * 从令牌中获取用户名 - * - * @param token 令牌 - * @return 用户名 - */ - private String getUsernameFromToken(String token) { - String username; - try { - Claims claims = jwtTokenUtil.getClaimsFromToken(token); - username = claims.getSubject(); - } catch (Exception e) { - username = null; - } - return username; - } - - private List getAuthoritiesFromToken(String token) { - List collAuthorities = new ArrayList(); - try { - Claims claims = jwtTokenUtil.getClaimsFromToken(token); - String roles = claims.get("roles", String.class); - - for (String role : roles.split(",")) { - collAuthorities.add(new SimpleGrantedAuthority(role)); - } - } catch (Exception e) { - collAuthorities = new ArrayList(); - } - return collAuthorities; - } - - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTTokenController.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTTokenController.java deleted file mode 100644 index 9a357f6..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTTokenController.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.supwisdom.infras.security.reactive.jwt; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.ReactiveUserDetailsService; -import org.springframework.util.MimeTypeUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RestController; - -import reactor.core.publisher.Mono; - -import com.supwisdom.infras.security.configure.jwt.util.SignUtil; -import com.supwisdom.infras.security.core.userdetails.InfrasUser; -import com.supwisdom.infras.security.utils.JWTTokenUtil; - -@RestController -public class JWTTokenController { - - private static final Logger logger = LoggerFactory.getLogger(JWTTokenController.class); - - @Value("${infras.security.jwt.token.sign.enabled:false}") - private boolean signEnabled; - @Value("${infras.security.jwt.token.sign.key:}") - private String signKey; - - @Value("${infras.security.jwt.token.authorization.prefix:Bearer}") - private String authorizationPrefix; - - @Autowired - private ReactiveAuthenticationManager reactiveAuthenticationManager; - @Autowired - private ReactiveUserDetailsService reactiveUserDetailsService; - @Autowired - private JWTTokenUtil jwtTokenUtil; - - /** - * 用户登录 - * - * curl -i -s -X POST 'http://localhost:8080/jwt/token/login' -d 'username=user&password=user' -H 'Content-Type: application/json' - * - * @param username 用户名 - * @param password 密码 - * @return 操作结果 - * @throws AuthenticationException 错误信息 - */ - @PostMapping(path = "/jwt/token/login", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) - public Mono login( - @RequestBody LoginRequest loginRequest - ) throws AuthenticationException { - - return Mono.just(loginRequest).flatMap(req -> { - try { - String username = req.getUsername(); - String password = req.getPassword(); - - // TODO:判断用户的登录频次 - - UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password); - - return reactiveAuthenticationManager.authenticate(upToken); - } catch (AuthenticationException e) { - // TODO: 记录失败 - throw e; - } - }).filter(a -> a.isAuthenticated() && a.getPrincipal() instanceof InfrasUser) - .map(Authentication::getPrincipal) - .cast(InfrasUser.class) - .map(userDetails -> { - String jwtToken = generateToken(userDetails); - return jwtToken; - }) - ; - - // 判断签名 -// if (signEnabled) { -// String timestamp = request.queryParam("timestamp").get(); -// String sign = request.queryParam("sign").get(); -// -// if (timestamp == null || timestamp.isEmpty()) { -// throw new BadCredentialsException("timestamp error"); -// } -// -// if (sign == null || sign.isEmpty()) { -// throw new BadCredentialsException("sign error"); -// } -// -// String data = timestamp + username + password; -// -// if (!SignUtil.checkIntervalTime(timestamp, 10000)) { -// throw new BadCredentialsException("timestamp error"); -// } -// -// String currentSign = SignUtil.HMACSHA1(data, signKey); -// if (!currentSign.equals(sign)) { -// throw new BadCredentialsException("sign error"); -// } -// } - -// String username = loginRequest.getUsername(); -// String password = loginRequest.getPassword(); -// -// // TODO:判断用户的登录频次 -// -// try { -// UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password); -// -// Mono token = -// reactiveAuthenticationManager.authenticate(upToken) -// .filter(a -> a.isAuthenticated() && a.getPrincipal() instanceof UserDetails) -// .map(Authentication::getPrincipal) -// .cast(UserDetails.class) -// .map(userDetails -> { -// String jwtToken = generateToken(userDetails); -// return jwtToken; -// }); -// -//// reactiveAuthenticationManager.authenticate(upToken) -//// .filter(a -> a.isAuthenticated() && a.getPrincipal() instanceof String) -//// .map(Authentication::getPrincipal) -//// .cast(String.class) -//// .map(principal -> { -//// return reactiveUserDetailsService.findByUsername(principal) -//// .map(userDetails -> { -//// String jwtToken = generateToken(userDetails); -//// return jwtToken; -//// }); -//// }); -// -// return token.block(); -// -//// reactiveAuthenticationManager.authenticate(upToken) -//// .filter(a -> a.isAuthenticated() && a.getPrincipal() instanceof UserDetails) -//// .map(Authentication::getPrincipal) -//// .cast(UserDetails.class) -//// .map(userDetails -> { -//// String jwtToken = generateToken(userDetails); -//// return jwtToken; -//// }) -//// ; -// -// } catch (AuthenticationException e) { -// // TODO: 记录失败 -// throw e; -// } -// -// //throw new UsernameNotFoundException(String.format("%s not found", username)); - } - - - /** - * 生成令牌 - * - * @param userDetails 用户 - * @return 令牌 - */ - private String generateToken(InfrasUser userDetails) { - String roles = ""; - for (GrantedAuthority ga : userDetails.getAuthorities()) { - String role = ga.getAuthority(); - roles += (roles.length() > 0 ? "," : "") + role; - } - - Map claims = new HashMap<>(); - claims.put("sub", userDetails.getUsername()); - claims.put("roles", roles); - claims.put("created", new Date()); - return jwtTokenUtil.generateToken(claims); - } - - - /** - * 刷新密钥 - * - * curl -i -s -X GET 'http://localhost:8080/jwt/token/refreshToken' -H 'Authorization: Bearer JWTToken' - * - * @param authorization 原密钥 - * @return 新密钥 - * @throws AuthenticationException 错误信息 - */ - @GetMapping(path = "/jwt/token/refreshToken") - public String refreshToken(@RequestHeader("Authorization") String authorization) throws AuthenticationException { - - if (authorization == null || !authorization.toLowerCase().startsWith(authorizationPrefix.toLowerCase())) { - return "authorization error"; - } - - String token = authorization.substring(authorizationPrefix.length() + 1); - //if (!jwtTokenUtil.isTokenExpired(token)) { - return jwtTokenUtil.refreshToken(token); - //} - - //return "error"; - } - - /** - * 注销密钥 - * - * curl -i -s -X GET 'http://localhost:8080/jwt/token/logout' -H 'Authorization: Bearer JWTToken' - * - * @param authorization 原密钥 - * @return - * @throws AuthenticationException - */ - @GetMapping(path = "/jwt/token/logout") - public String expireToken(@RequestHeader("Authorization") String authorization) throws AuthenticationException { - - if (authorization == null || !authorization.toLowerCase().startsWith(authorizationPrefix.toLowerCase())) { - return "authorization error"; - } - - String token = authorization.substring(authorizationPrefix.length() + 1); - - jwtTokenUtil.expireToken(token); - - return "success"; - } - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTWebFluxConfiguration.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTWebFluxConfiguration.java deleted file mode 100644 index 014e483..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/JWTWebFluxConfiguration.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.supwisdom.infras.security.reactive.jwt; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager; -import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.core.userdetails.ReactiveUserDetailsService; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; - -import com.supwisdom.infras.security.utils.JWTTokenUtil; - -@Configuration -@ConditionalOnProperty(name="infras.security.jwt.reactive.enabled", havingValue="true") -public class JWTWebFluxConfiguration { - - private static final Logger logger = LoggerFactory.getLogger(JWTWebFluxConfiguration.class); - -// @ConditionalOnClass(RedisConnectionFactory.class) -// @Configuration -// public static class RedisStoreConfiguration { -// -// @Bean -// public JWTTokenRedisStore jwtTokenRedisStore(RedisConnectionFactory connectionFactory) { -// -// JWTTokenRedisStore jwtTokenRedisStore = new JWTTokenRedisStore(connectionFactory); -// -// return jwtTokenRedisStore; -// } -// -// } - - @Autowired(required = false) - private ReactiveUserDetailsService reactiveUserDetailsService; - - @Autowired(required = false) - private PasswordEncoder passwordEncoder; - - @Bean - public ReactiveAuthenticationManager reactiveAuthenticationManager() { - if(this.reactiveUserDetailsService != null) { - UserDetailsRepositoryReactiveAuthenticationManager manager = - new UserDetailsRepositoryReactiveAuthenticationManager(this.reactiveUserDetailsService); - if(this.passwordEncoder != null) { - manager.setPasswordEncoder(this.passwordEncoder); - } - return manager; - } - return null; - } - - @Bean - public JWTTokenUtil jwtTokenUtil() { - - return new JWTTokenUtil(); - } - - @Bean - JWTKeyController jwtKeyController() { - - JWTKeyController jwtKeyController = new JWTKeyController(); - logger.debug("JWTWebFluxConfiguration jwtKeyController is {}", jwtKeyController); - - return jwtKeyController; - } - - - - @Bean - public JWTTokenController jwtTokenController() { - - JWTTokenController jwtTokenController = new JWTTokenController(); - logger.debug("JWTWebFluxConfiguration jwtTokenController is {}", jwtTokenController); - - return jwtTokenController; - } - - @Bean - public JWTSecurityContextRepository jwtSecurityContextRepository(JWTTokenUtil jwtTokenUtil) { - JWTSecurityContextRepository jwtSecurityContextRepository = new JWTSecurityContextRepository(jwtTokenUtil); - - return jwtSecurityContextRepository; - } - - - @Bean - public SecurityWebFilterChain jwtTokenSpringSecurityFilterChain(ServerHttpSecurity http) { - - logger.debug("jwtTokenSpringSecurityFilterChain(ServerHttpSecurity)"); - - http - .securityMatcher(ServerWebExchangeMatchers.pathMatchers("/jwt/**")) - .authorizeExchange() - .pathMatchers(HttpMethod.OPTIONS).permitAll() - .pathMatchers("/jwt/publicKey").permitAll() - .pathMatchers("/jwt/**").permitAll() - .anyExchange().authenticated(); - - http.httpBasic().disable(); - http.formLogin().disable(); - - http.csrf().disable(); - - return http.build(); - } - - - - @Bean - public SecurityWebFilterChain jwtApiSpringSecurityFilterChain(ServerHttpSecurity http) { - http - .securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/**")) - .authorizeExchange() - .pathMatchers(HttpMethod.OPTIONS).permitAll() - .pathMatchers("/api/public/**", "/api/open/**").permitAll() - .pathMatchers("/api/v*/public/**", "/api/v*/open/**").permitAll() - .pathMatchers("/api/*/v*/public/**", "/api/*/v*/open/**").permitAll() - .pathMatchers("/api/**").authenticated() - .anyExchange().authenticated(); - - //http.addFilterAt(webFilter, SecurityWebFiltersOrder.LAST); - - http.securityContextRepository(jwtSecurityContextRepository(jwtTokenUtil())); - - http.httpBasic().disable(); - http.formLogin().disable(); - - http.csrf().disable(); - - return http.build(); - } - - -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/LoginRequest.java b/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/LoginRequest.java deleted file mode 100644 index 2e47c2c..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/reactive/jwt/LoginRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.supwisdom.infras.security.reactive.jwt; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class LoginRequest { - private String username; - private String password; -} diff --git a/gateway/src/main/java/com/supwisdom/infras/security/utils/JWTTokenUtil.java b/gateway/src/main/java/com/supwisdom/infras/security/utils/JWTTokenUtil.java deleted file mode 100644 index abbf378..0000000 --- a/gateway/src/main/java/com/supwisdom/infras/security/utils/JWTTokenUtil.java +++ /dev/null @@ -1,261 +0,0 @@ -package com.supwisdom.infras.security.utils; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; - -import java.io.IOException; -import java.security.KeyPair; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -//import org.springframework.security.core.GrantedAuthority; -//import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Component; - -import com.supwisdom.infras.security.cert.CertUtil; -import com.supwisdom.infras.security.token.store.redis.JWTTokenRedisStore; - -@Component -public class JWTTokenUtil implements InitializingBean { - - private static final Logger logger = LoggerFactory.getLogger(JWTTokenUtil.class); - - private static ConcurrentMap mapTokenExpiration = new ConcurrentHashMap(); - - @Autowired(required = false) - private JWTTokenRedisStore redisTokenStore; - - /** - * 密钥 - */ - //@Value("${infras.security.jwt.secret:MyJwtSecret}") - //private String secret; - - - @Value("${infras.security.jwt.iss:supwisdom}") - private String issuer; - @Value("${infras.security.jwt.jti:supwisdom-jwt}") - private String jti; - - - @Value("${infras.security.jwt.expiration:2592000}") - private Long expiration; - - @Value("${infras.security.jwt.kickout.enabled:false}") - private boolean kickoutEnabled; - - - @Value("${infras.security.jwt.key-alias:supwisdom-jwt-key}") - private String keyAlias; - @Value("${infras.security.jwt.key-password:kingstar}") - private String keyPassword; - - @Value("${infras.security.jwt.key-store:}") - private String keyStore; - @Value("${infras.security.jwt.key-store-password:kingstar}") - private String keyStorePassword; - - - @Value("${infras.security.jwt.public-key-pem:}") - private String publicKeyPem; - @Value("${infras.security.jwt.private-key-pem-pkcs8:}") - private String privateKeyPemPKCS8; - - @Override - public void afterPropertiesSet() throws Exception { - this.initKey(); - } - - private KeyPair keyPair; - - public void initKey() { - - try { - this.keyPair = CertUtil.initKeyFromPem(publicKeyPem, privateKeyPemPKCS8); - logger.debug("init keyPair from pem"); - return; - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - e.printStackTrace(); - } - - try { - this.keyPair = CertUtil.initKeyFromKeyStore(keyStore, keyStorePassword, keyAlias, keyPassword); - logger.debug("init keyPair from keyStore"); - } catch (UnrecoverableKeyException e) { - e.printStackTrace(); - } catch (KeyStoreException e) { - e.printStackTrace(); - } catch (CertificateException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - - } - - public RSAPublicKey getPublicKey() { - return (RSAPublicKey) this.keyPair.getPublic(); - } - - public RSAPrivateKey getPrivateKey() { - return (RSAPrivateKey) this.keyPair.getPrivate(); - } - - public String getPublicKeyPem() { - return CertUtil.publicKeyToPem(getPublicKey()); - } - - private void storeTokenExpiration(String token, Long expiration) { - if (!kickoutEnabled) { - return; - } - - logger.debug("store to Map"); - mapTokenExpiration.put(token, expiration); // FIXME: 存储到 redis 或 数据库 - - if (redisTokenStore != null) { - logger.debug("store to Redis"); - redisTokenStore.storeTokenExpiration(token, expiration); - } - } - - private Long loadTokenExpiration(String token) { - if (!kickoutEnabled) { - return Long.MAX_VALUE; - } - - if (redisTokenStore != null) { - logger.debug("load from Redis"); - return redisTokenStore.loadTokenExpiration(token, -1L); - } - - logger.debug("load from Map"); - return mapTokenExpiration.getOrDefault(token, -1L); // FIXME: 存储到 redis 或 数据库 - } - - /** - * 从数据声明生成令牌 - * - * @param claims 数据声明 - * @return 令牌 - */ - public String generateToken(Map claims) { - Date expirationDate = new Date(System.currentTimeMillis() + expiration * 1000); - String token = Jwts.builder() - .setClaims(claims) - .setIssuer(issuer) - .setId(jti) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(expirationDate) - .signWith(SignatureAlgorithm.RS512, this.getPrivateKey()) - .compact(); - - storeTokenExpiration(token, expirationDate.getTime()); - - return token; - } - - /** - * 从令牌中获取数据声明 - * - * @param token 令牌 - * @return 数据声明 - */ - public Claims getClaimsFromToken(String token) { - Claims claims; - try { - claims = Jwts.parser().setSigningKey(this.getPublicKey()).parseClaimsJws(token).getBody(); - } catch (Exception e) { - claims = null; - } - return claims; - } - - /** - * 判断令牌是否过期 - * - * @param token 令牌 - * @return 是否过期 - */ - public Boolean isTokenExpired(String token) { - try { - Claims claims = getClaimsFromToken(token); - Date expiration = claims.getExpiration(); - - Date now = new Date(); - - // 判断存储中的 token 是否过期 - Long expirationTimeMillis = loadTokenExpiration(token); - if (expirationTimeMillis < now.getTime()) { - return true; - } - - return expiration.before(now); - } catch (Exception e) { - return false; // FIXME: ? - } - } - - /** - * 刷新令牌 - * - * @param token 原令牌 - * @return 新令牌 - */ - public String refreshToken(String token) { - String refreshedToken; - try { - Claims claims = getClaimsFromToken(token); - claims.put("created", new Date()); - refreshedToken = generateToken(claims); - } catch (Exception e) { - refreshedToken = null; - } - return refreshedToken; - } - - /** - * 验证令牌 - * - * @param token 令牌 - * @param userDetails 用户 - * @return 是否有效 - */ - public Boolean validateToken(String token, String username) { - Claims claims = getClaimsFromToken(token); - String sub = claims.getSubject(); - - return (sub.equals(username) && !isTokenExpired(token)); - } - - /** - * 踢出令牌 - * @param token - */ - public void expireToken(String token) { - if (!isTokenExpired(token)) { - storeTokenExpiration(token, -1L); - } - } - -} diff --git a/gateway/src/main/resources/META-INF/spring.factories b/gateway/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 9a872fd..0000000 --- a/gateway/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,3 +0,0 @@ -# Auto Configure -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.supwisdom.infras.security.reactive.InfrasSecurityReactiveAutoConfiguration \ No newline at end of file -- 2.17.1