mirror of https://github.com/longtai-cn/hippo4j
客户端交互服务端依赖 AccessToken. (#34)
parent
22af663eb1
commit
fe66c716b5
@ -0,0 +1,46 @@
|
|||||||
|
package cn.hippo4j.auth.security;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.expression.AccessException;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auth manager
|
||||||
|
*
|
||||||
|
* @author chen.ma
|
||||||
|
* @date 2021/12/20 20:34
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AuthManager {
|
||||||
|
|
||||||
|
private final JwtTokenManager jwtTokenManager;
|
||||||
|
|
||||||
|
private final AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve token from user.
|
||||||
|
*
|
||||||
|
* @param userName
|
||||||
|
* @param rawPassword
|
||||||
|
* @return
|
||||||
|
* @throws AccessException
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public String resolveTokenFromUser(String userName, String rawPassword) {
|
||||||
|
try {
|
||||||
|
UsernamePasswordAuthenticationToken authenticationToken =
|
||||||
|
new UsernamePasswordAuthenticationToken(userName, rawPassword);
|
||||||
|
authenticationManager.authenticate(authenticationToken);
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
throw new AccessException("Unknown user.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwtTokenManager.createToken(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package cn.hippo4j.auth.security;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.hippo4j.auth.constant.Constants.TOKEN_VALIDITY_IN_SECONDS;
|
||||||
|
import static cn.hippo4j.auth.toolkit.JwtTokenUtil.SECRET;
|
||||||
|
import static cn.hippo4j.common.constant.Constants.AUTHORITIES_KEY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jwt token manager.
|
||||||
|
*
|
||||||
|
* @author chen.ma
|
||||||
|
* @date 2021/12/20 20:36
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JwtTokenManager {
|
||||||
|
|
||||||
|
public String createToken(String userName) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
Date validity;
|
||||||
|
validity = new Date(now + TOKEN_VALIDITY_IN_SECONDS * 1000L);
|
||||||
|
|
||||||
|
Claims claims = Jwts.claims().setSubject(userName);
|
||||||
|
return Jwts.builder().setClaims(claims).setExpiration(validity)
|
||||||
|
.signWith(SignatureAlgorithm.HS512, SECRET).compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateToken(String token) {
|
||||||
|
Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get auth Info.
|
||||||
|
*
|
||||||
|
* @param token token
|
||||||
|
* @return auth info
|
||||||
|
*/
|
||||||
|
public Authentication getAuthentication(String token) {
|
||||||
|
Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
|
||||||
|
|
||||||
|
List<GrantedAuthority> authorities = AuthorityUtils
|
||||||
|
.commaSeparatedStringToAuthorityList((String) claims.get(AUTHORITIES_KEY));
|
||||||
|
|
||||||
|
User principal = new User(claims.getSubject(), StrUtil.EMPTY, authorities);
|
||||||
|
return new UsernamePasswordAuthenticationToken(principal, StrUtil.EMPTY, authorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package cn.hippo4j.common.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token info.
|
||||||
|
*
|
||||||
|
* @author chen.ma
|
||||||
|
* @date 2021/12/20 20:02
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class TokenInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* accessToken
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tokenTtl
|
||||||
|
*/
|
||||||
|
private Long tokenTtl;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
package cn.hippo4j.starter.security;
|
||||||
|
|
||||||
|
import cn.hippo4j.common.constant.Constants;
|
||||||
|
import cn.hippo4j.common.model.TokenInfo;
|
||||||
|
import cn.hippo4j.common.toolkit.JSONUtil;
|
||||||
|
import cn.hippo4j.common.web.base.Result;
|
||||||
|
import cn.hippo4j.starter.config.BootstrapProperties;
|
||||||
|
import cn.hippo4j.starter.toolkit.HttpClientUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security proxy.
|
||||||
|
*
|
||||||
|
* @author chen.ma
|
||||||
|
* @date 2021/12/20 20:19
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SecurityProxy {
|
||||||
|
|
||||||
|
private static final String APPLY_TOKEN_URL = Constants.BASE_PATH + "/auth/users/apply/token";
|
||||||
|
|
||||||
|
private final HttpClientUtil httpClientUtil;
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
private long tokenTtl;
|
||||||
|
|
||||||
|
private long lastRefreshTime;
|
||||||
|
|
||||||
|
private long tokenRefreshWindow;
|
||||||
|
|
||||||
|
public SecurityProxy(HttpClientUtil httpClientUtil, BootstrapProperties properties) {
|
||||||
|
username = properties.getUsername();
|
||||||
|
password = properties.getPassword();
|
||||||
|
this.httpClientUtil = httpClientUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean applyToken(List<String> servers) {
|
||||||
|
try {
|
||||||
|
if ((System.currentTimeMillis() - lastRefreshTime) < TimeUnit.SECONDS
|
||||||
|
.toMillis(tokenTtl - tokenRefreshWindow)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String server : servers) {
|
||||||
|
if (applyToken(server)) {
|
||||||
|
lastRefreshTime = System.currentTimeMillis();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean applyToken(String server) {
|
||||||
|
if (StrUtil.isAllNotBlank(username, password)) {
|
||||||
|
String url = server + APPLY_TOKEN_URL;
|
||||||
|
|
||||||
|
Map<String, String> bodyMap = new HashMap(2);
|
||||||
|
bodyMap.put("userName", username);
|
||||||
|
bodyMap.put("password", password);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Result<String> result = httpClientUtil.restApiPost(url, bodyMap, Result.class);
|
||||||
|
if (!result.isSuccess()) {
|
||||||
|
log.error("Error getting access token. message :: {}", result.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String tokenJsonStr = JSONUtil.toJSONString(result.getData());
|
||||||
|
TokenInfo tokenInfo = JSONUtil.parseObject(tokenJsonStr, TokenInfo.class);
|
||||||
|
|
||||||
|
accessToken = tokenInfo.getAccessToken();
|
||||||
|
tokenTtl = tokenInfo.getTokenTtl();
|
||||||
|
tokenRefreshWindow = tokenTtl / 10;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("Failed to apply for token. message :: {}", ex.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in new issue