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