I am going to implement JWT authentication for several independent services. There will be auth.example.com and service1.example.com, service2.example.com etc.
My assumptions:
我正在实现一个使用 OAuth2 针对 WSO2 进行身份验证的客户端,但在刷新访问令牌时遇到了严重的问题,获得 401 UNAUTHORIZED。虽然我已经发现了 Spring OAuth2 代码的作用,但我不知道为什么它的行为在 2.2.1.RELEASE 中发生了变化,对我来说这似乎是完全错误的。实际上使用 2.0.14.RELEASE 是有效的。
在我向你展示我做了什么以及我已经发现了什么之前,让我提出我的问题:
我应该如何使用客户端凭据而不是用户凭据来实现带有自动令牌刷新的 OAuth2 客户端?
所以这就是我到目前为止所实施的。客户端的配置OAuth2RestTemplate与ResourceOwnerPasswordResourceDetails用isClientOnly标志true,因为没有用户会话。可以成功建立客户端会话并设置访问令牌和刷新令牌。
@Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails() {
@Override
public boolean isClientOnly() {
return true;
}
};
List<String> scopes = new ArrayList<>(2);
scopes.add("write");
scopes.add("read");
resource.setScope(scopes);
resource.setGrantType("password");
resource.setAccessTokenUri(TOKEN_URL);
resource.setClientId(MY_CLIENT_ID);
resource.setClientSecret(MY_CLIENT_SECRET);
resource.setUsername(MY_SERVICE_USER);
resource.setPassword(MY_SERVICE_USER_PW);
return resource;
}
@Bean
public OAuth2RestOperations restTemplate() {
AccessTokenRequest atr = new DefaultAccessTokenRequest();
OAuth2RestTemplate template = new OAuth2RestTemplateWithBasicAuth(resource(), new …Run Code Online (Sandbox Code Playgroud) 我是 spring 的新手,我正在使用 spring 安全性开发 spring boot REST,目前我实现了 JWT 令牌。我有一些问题,但似乎无法找到答案。我尝试添加刷新令牌。
起初我以为我会将它与用户一起存储在数据库中,但是 Spring Security 会自动完成所有操作,而且我似乎无法找到如何将它存储在表用户的给定字段中。
所以,继续我决定我会尝试坚持使用 spring 安全自动化,我将刷新令牌过期时间设置为 10 秒来测试它是否过期,但遗憾的是它没有按预期工作 - 我可以使用刷新令牌,只要我想并用它生成新的令牌。
所以在这里我有几个问题:
1. 如何使刷新令牌在给定时间后过期?这是我的安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.signing-key}")
private String signingKey;
@Value("${security.encoding-strength}")
private Integer encodingStrength;
@Value("${security.security-realm}")
private String securityRealm;
@Autowired
private UserDetailsService userDetailsService;
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = …Run Code Online (Sandbox Code Playgroud) 我正在使用 AWS 的 Cognito 进行测试。在这一点上,我可以找回我的IdToken, AccessToken, 并且RefreshToken像这样:
$ aws cognito-idp admin-initiate-auth --user-pool-id us-east-1_XXXXXXXX --client-id XXXXXXXXXXXXXXXXXXXXXXX --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=XXXXXXXXXXXXX,PASSWORD=XXXXXXXXXXXXX --region us-east-1
Run Code Online (Sandbox Code Playgroud)
然后我在这样的 URL 上尝试了默认网页(由 Cognito 提供):
https://test-cognito.auth.us-east-1.amazoncognito.com/login?response_type=token&client_id=XXXXXXXXXXXXXXXXXXXXXX&redirect_uri=https://example.com
Run Code Online (Sandbox Code Playgroud)
此 URL 将带我到一个页面,我必须在其中进行身份验证,一旦该过程完成,它将带我回到我redirect_url附加的前面提到的 ID:
https://example.com#id_token=XXXXX.XXXXXX.XXXXXX&access_token=XXXXXX.XXXXXXX.XXXXXXX&expires_in=3600&token_type=Bearer
Run Code Online (Sandbox Code Playgroud)
但是没有任何迹象refresh_token!refresh_token在这种情况下我怎样才能得到我的?
场景是:您拥有有效期较长的刷新令牌和有效期较短的访问令牌。
设置:有客户端、应用程序服务器和身份验证服务器。
优点之一是被盗的访问令牌只能在其有效时间内使用。
假设黑客窃取了有效期为 30 分钟的访问令牌。当黑客在 30 分钟后使用有效但已过期的被盗访问令牌进行请求时,应用服务器将使用刷新令牌对其进行刷新,从而黑客获得一个新的有效且未过期的访问令牌。
如何防止这种情况发生?
我正在尝试使用 ClientOAuth2.Token.refresh() 刷新 oauth2 令牌,但有时会不断收到错误消息:
{"error":"invalid_grant","error_description":"Session not active"}
这是我被 Fiddler 捕获的请求
POST [URL]= HTTP/1.1
Host: [URL]
Connection: keep-alive
Content-Length: 2250
Accept: application/json, application/x-www-form-urlencoded
Origin: http://localhost:8080
Authorization: Basic YXNpbW92LWRldi1laGlzLXdlYjo=
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Sec-Fetch-Mode: cors
Content-Type: application/x-www-form-urlencoded
Sec-Fetch-Site: cross-site
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: en,vi;q=0.9,de;q=0.8,vi-VN;q=0.7,en-US;q=0.6,en-AU;q=0.5
refresh_token=[token]&grant_type=refresh_token
Run Code Online (Sandbox Code Playgroud)
也许我在 KeyCloak 帐户上的设置有问题。有什么建议吗?
我正在使用 Identity Server 4 示例代码。特别是,对于客户端,我使用带有混合流的示例 MVC 客户端:https : //github.com/IdentityServer/IdentityServer4/tree/master/samples/Clients/src/MvcHybrid
对于服务器,我将 Identity Server 与内存客户端一起使用(没有实体框架,也没有 ASP.Net Identity):https : //github.com/IdentityServer/IdentityServer4/tree/master/samples/Quickstarts
客户端和服务器都有非常普通的、开箱即用的配置。
我试图了解刷新令牌如何过期以及本机应用程序如何主动确定过期时间(在它被 API 拒绝之前)。我的理解是刷新令牌的默认到期时间很长:
http://docs.identityserver.io/en/latest/topics/refresh_tokens.html:
刷新令牌的最长生命周期(以秒为单位)。默认为 2592000 秒/30 天
但是,当示例代码请求刷新令牌时,我没有得到预期的到期时间。这是示例代码:
var disco = await _discoveryCache.GetAsync();
if (disco.IsError) throw new Exception(disco.Error);
var rt = await HttpContext.GetTokenAsync("refresh_token");
var tokenClient = _httpClientFactory.CreateClient();
var tokenResult = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "mvc.hybrid",
ClientSecret = "secret",
RefreshToken = rt
});
Run Code Online (Sandbox Code Playgroud)
tokenResult.ExpiresIn是 3600 秒,这实际上是访问令牌的到期时间。我原以为是 2592000 秒。所以问题#1 是: 为什么会这样?
但更重要的是,我知道刷新令牌的到期实际上是我使用 SQL Server …
使用 JWT 的 API 请求在 Flask 和 Vue.js 中实现。JWT 存储在 cookie 中,服务器为每个请求验证 JWT。
如果令牌已过期,将返回 401 错误。如果您收到 401 错误,请按照以下代码刷新令牌,再次发出原始 API 请求。以下代码适用于所有请求。
http.interceptors.response.use((response) => {
return response;
}, error => {
if (error.config && error.response && error.response.status === 401 && !error.config._retry) {
error.config._retry = true;
http
.post(
"/token/refresh",
{},
{
withCredentials: true,
headers: {
"X-CSRF-TOKEN": Vue.$cookies.get("csrf_refresh_token")
}
}
)
.then(res => {
if (res.status == 200) {
const config = error.config;
config.headers["X-CSRF-TOKEN"] = Vue.$cookies.get("csrf_access_token");
return Axios.request(error.config);
}
})
.catch(error => {
}); …Run Code Online (Sandbox Code Playgroud) 这一行:
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
Run Code Online (Sandbox Code Playgroud)
当我的 jwt 令牌过期时抛出这样的错误:
JWT 于 2020-05-13T07:50:39Z 过期。当前时间:2020-05-16T21:29:41Z。
更具体地说,正是这个函数抛出了“ExpiredJwtException”异常:

我该如何处理这些异常?我是否应该捕获它们并将错误消息发送回客户端并强制它们重新登录?
如何实现刷新令牌功能?我在后端使用 Spring 和 mysql,在前端使用 vuejs。
我生成这样的初始令牌:
@Override
public JSONObject login(AuthenticationRequest authreq) {
JSONObject json = new JSONObject();
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authreq.getUsername(), authreq.getPassword()));
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
.collect(Collectors.toList());
if (userDetails != null) {
final String jwt = jwtTokenUtil.generateToken(userDetails);
JwtResponse jwtres = new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(),
userDetails.getEmail(), roles, jwtTokenUtil.extractExpiration(jwt).toString());
return json.put("jwtresponse", jwtres);
}
} catch (BadCredentialsException ex) {
json.put("status", "badcredentials"); …Run Code Online (Sandbox Code Playgroud) refresh-token ×10
jwt ×6
access-token ×4
oauth-2.0 ×4
keycloak ×2
spring ×2
axios ×1
c# ×1
java ×1
javascript ×1
spring-boot ×1
token ×1