Kum*_*hav 5 spring-security spring-security-oauth2
参考oauth2 spring-guides项目中的注销流程,一旦用户首次使用用户名/密码进行了身份验证,则注销后下次将不要求提供凭据。
如何确保每次注销后都要求输入用户名/密码。
这就是我要实现的:
OAuth2服务器使用具有自动批准功能的“ authorization_code”授予类型发布JWT令牌。这具有html / angularjs表单来收集用户名/密码。
UI / Webfront-使用@EnableSSO。其所有端点均已通过身份验证,即,它没有用户单击以转到/ uaa服务器的任何未经授权的登录页面/ ui /链接。因此,点击http:// localhost:8080会 立即将您重定向到http:// localhost:9999 / uaa并显示自定义表单以收集用户名/密码。
使用上述方法,我无法锻炼注销流程。到UI应用程序的HTTP POST / logout清除了UI应用程序中的会话/身份验证,但用户再次自动登录(因为我选择了所有范围的自动批准),而无需再次询问用户名密码。
查看日志和网络呼叫,似乎所有“ oauth舞动”都成功地再次发生,而无需再次要求用户输入用户名/密码,并且似乎auth服务器记住了为客户端发布的最后一个auth令牌(使用org.springframework .security.oauth2.provider.code.InMemoryAuthorizationCodeServices?)。
我如何告诉认证服务器每次要求输入用户名/密码的代码/令牌-无状态。
还是在给定方案中实现注销的最佳方法是什么。
(要重新创建一些接近我的要求的内容,请permitAll()从UiApplication中删除一部分,然后autoApproval在上述启动项目的身份验证服务器中进行配置。)
我也遇到了您所描述的错误,并且我从问题 Spring Boot OAuth2 Single Sign Off中看到了解决方案。我并不是说这是唯一的、全球性的真相解决方案。
但在场景中,
您需要从身份验证服务器的会话中删除身份验证信息,如此答案所述。
下面的片段是我如何配置解决方案
客户端(在您的情况下为 UI 应用程序)应用程序的 WebSecurityConfig
...
@Value("${auth-server}/ssoLogout")
private String logoutUrl;
@Autowired
private CustomLogoutHandler logoutHandler;
...
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutSuccessUrl(logoutUrl)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.addLogoutHandler(logoutHandler)
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
// @formatter:on
}
Run Code Online (Sandbox Code Playgroud)
客户端应用程序的自定义注销处理程序
@Component
public class CustomLogoutHandler implements LogoutHandler {
private static Logger logger = Logger.getLogger(CustomLogoutHandler.class);
@Value("${auth-server}/invalidateTokens")
private String logoutUrl;
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
logger.debug("Excution CustomLogoutHandler for " + authentication.getName());
Object details = authentication.getDetails();
if (details.getClass().isAssignableFrom(OAuth2AuthenticationDetails.class)) {
String accessToken = ((OAuth2AuthenticationDetails) details).getTokenValue();
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("access_token", accessToken);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "bearer " + accessToken);
HttpEntity<Object> entity = new HttpEntity<>(params, headers);
HttpMessageConverter<?> formHttpMessageConverter = new FormHttpMessageConverter();
HttpMessageConverter<?> stringHttpMessageConverternew = new StringHttpMessageConverter();
restTemplate.setMessageConverters(Arrays.asList(new HttpMessageConverter[] { formHttpMessageConverter, stringHttpMessageConverternew }));
try {
ResponseEntity<String> serverResponse = restTemplate.exchange(logoutUrl, HttpMethod.POST, entity, String.class);
logger.debug("Server Response : ==> " + serverResponse);
} catch (HttpClientErrorException e) {
logger.error("HttpClientErrorException invalidating token with SSO authorization server. response.status code: " + e.getStatusCode() + ", server URL: " + logoutUrl);
}
}
authentication.setAuthenticated(false);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
new SecurityContextLogoutHandler().logout(request, response, auth);
}
}
Run Code Online (Sandbox Code Playgroud)
我使用了 JDBC tokenStore,所以我需要撤销令牌。在身份验证服务器端,我添加了一个控制器来处理注销过程
@Controller
public class AuthenticationController {
private static Logger logger = Logger.getLogger(AuthenticationController.class);
@Resource(name = "tokenStore")
private TokenStore tokenStore;
@Resource(name = "approvalStore")
private ApprovalStore approvalStore;
@RequestMapping(value = "/invalidateTokens", method = RequestMethod.POST)
public @ResponseBody Map<String, String> revokeAccessToken(HttpServletRequest request, HttpServletResponse response, @RequestParam(name = "access_token") String accessToken, Authentication authentication) {
if (authentication instanceof OAuth2Authentication) {
logger.info("Revoking Approvals ==> " + accessToken);
OAuth2Authentication auth = (OAuth2Authentication) authentication;
String clientId = auth.getOAuth2Request().getClientId();
Authentication user = auth.getUserAuthentication();
if (user != null) {
Collection<Approval> approvals = new ArrayList<Approval>();
for (String scope : auth.getOAuth2Request().getScope()) {
approvals.add(new Approval(user.getName(), clientId, scope, new Date(), ApprovalStatus.APPROVED));
}
approvalStore.revokeApprovals(approvals);
}
}
logger.info("Invalidating access token :- " + accessToken);
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken);
if (oAuth2AccessToken != null) {
if (tokenStore instanceof JdbcTokenStore) {
logger.info("Invalidating Refresh Token :- " + oAuth2AccessToken.getRefreshToken().getValue());
((JdbcTokenStore) tokenStore).removeRefreshToken(oAuth2AccessToken.getRefreshToken());
tokenStore.removeAccessToken(oAuth2AccessToken);
}
}
Map<String, String> ret = new HashMap<>();
ret.put("removed_access_token", accessToken);
return ret;
}
@GetMapping("/ssoLogout")
public void exit(HttpServletRequest request, HttpServletResponse response) throws IOException {
new SecurityContextLogoutHandler().logout(request, null, null);
// my authorization server's login form can save with remember-me cookie
Cookie cookie = new Cookie("my_rememberme_cookie", null);
cookie.setMaxAge(0);
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
response.addCookie(cookie);
response.sendRedirect(request.getHeader("referer"));
}
}
Run Code Online (Sandbox Code Playgroud)
在授权服务器的 SecurityConfig 中,您可能需要允许此 url 作为
http
.requestMatchers()
.antMatchers(
"/login"
,"/ssoLogout"
,"/oauth/authorize"
,"/oauth/confirm_access");
Run Code Online (Sandbox Code Playgroud)
我希望这对你有一点帮助。
| 归档时间: |
|
| 查看次数: |
1053 次 |
| 最近记录: |