- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 Spring Boot (v1.5.10.RELEASE) 为用 Angular 编写的应用程序创建后端。背面使用 Spring 安全 + key 斗篷固定。现在我正在添加一个 websocket,使用 STOMP over SockJS,并希望保护它。我正在尝试关注 Websocket Token Authentication 上的文档,并显示以下代码:
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
Authentication user = ... ; // access authentication header(s)
accessor.setUser(user);
}
String token = accessor.getNativeHeader("Authorization").get(0);
@Configuration
public class WebSocketSecurityConfig extends
AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry
messages) {
messages.simpDestMatchers("/app/**").authenticated().simpSubscribeDestMatchers("/topic/**").authenticated()
.anyMessage().denyAll();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class WebSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authenticationProvider(keycloakAuthenticationProvider())
.addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.authorizeRequests()
.requestMatchers(new NegatedRequestMatcher(new AntPathRequestMatcher("/management/**")))
.hasRole("USER");
}
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
最佳答案
根据 Raman 对 this question 的建议,我能够启用基于 token 的身份验证。这是使其工作的最终代码:
1) 首先,创建一个代表 JWS 身份验证 token 的类:
public class JWSAuthenticationToken extends AbstractAuthenticationToken implements Authentication {
private static final long serialVersionUID = 1L;
private String token;
private User principal;
public JWSAuthenticationToken(String token) {
this(token, null, null);
}
public JWSAuthenticationToken(String token, User principal, Collection<GrantedAuthority> authorities) {
super(authorities);
this.token = token;
this.principal = principal;
}
@Override
public Object getCredentials() {
return token;
}
@Override
public Object getPrincipal() {
return principal;
}
}
@Slf4j
@Component
@Qualifier("websocket")
@AllArgsConstructor
public class KeycloakWebSocketAuthManager implements AuthenticationManager {
private final KeycloakTokenVerifier tokenVerifier;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
JWSAuthenticationToken token = (JWSAuthenticationToken) authentication;
String tokenString = (String) token.getCredentials();
try {
AccessToken accessToken = tokenVerifier.verifyToken(tokenString);
List<GrantedAuthority> authorities = accessToken.getRealmAccess().getRoles().stream()
.map(SimpleGrantedAuthority::new).collect(Collectors.toList());
User user = new User(accessToken.getName(), accessToken.getEmail(), accessToken.getPreferredUsername(),
accessToken.getRealmAccess().getRoles());
token = new JWSAuthenticationToken(tokenString, user, authorities);
token.setAuthenticated(true);
} catch (VerificationException e) {
log.debug("Exception authenticating the token {}:", tokenString, e);
throw new BadCredentialsException("Invalid token");
}
return token;
}
}
@Component
@AllArgsConstructor
public class KeycloakTokenVerifier {
private final KeycloakProperties config;
/**
* Verifies a token against a keycloak instance
* @param tokenString the string representation of the jws token
* @return a validated keycloak AccessToken
* @throws VerificationException when the token is not valid
*/
public AccessToken verifyToken(String tokenString) throws VerificationException {
RSATokenVerifier verifier = RSATokenVerifier.create(tokenString);
PublicKey publicKey = retrievePublicKeyFromCertsEndpoint(verifier.getHeader());
return verifier.realmUrl(getRealmUrl()).publicKey(publicKey).verify().getToken();
}
@SuppressWarnings("unchecked")
private PublicKey retrievePublicKeyFromCertsEndpoint(JWSHeader jwsHeader) {
try {
ObjectMapper om = new ObjectMapper();
Map<String, Object> certInfos = om.readValue(new URL(getRealmCertsUrl()).openStream(), Map.class);
List<Map<String, Object>> keys = (List<Map<String, Object>>) certInfos.get("keys");
Map<String, Object> keyInfo = null;
for (Map<String, Object> key : keys) {
String kid = (String) key.get("kid");
if (jwsHeader.getKeyId().equals(kid)) {
keyInfo = key;
break;
}
}
if (keyInfo == null) {
return null;
}
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusBase64 = (String) keyInfo.get("n");
String exponentBase64 = (String) keyInfo.get("e");
Decoder urlDecoder = Base64.getUrlDecoder();
BigInteger modulus = new BigInteger(1, urlDecoder.decode(modulusBase64));
BigInteger publicExponent = new BigInteger(1, urlDecoder.decode(exponentBase64));
return keyFactory.generatePublic(new RSAPublicKeySpec(modulus, publicExponent));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String getRealmUrl() {
return String.format("%s/realms/%s", config.getAuthServerUrl(), config.getRealm());
}
public String getRealmCertsUrl() {
return getRealmUrl() + "/protocol/openid-connect/certs";
}
}
@Slf4j
@Configuration
@EnableWebSocketMessageBroker
@AllArgsConstructor
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
@Qualifier("websocket")
private AuthenticationManager authenticationManager;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-paperless").setAllowedOrigins("*").withSockJS();
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptorAdapter() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
Optional.ofNullable(accessor.getNativeHeader("Authorization")).ifPresent(ah -> {
String bearerToken = ah.get(0).replace("Bearer ", "");
log.debug("Received bearer token {}", bearerToken);
JWSAuthenticationToken token = (JWSAuthenticationToken) authenticationManager
.authenticate(new JWSAuthenticationToken(bearerToken));
accessor.setUser(token);
});
}
return message;
}
});
}
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/ws-endpoint/**");
}
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages.simpTypeMatchers(CONNECT, UNSUBSCRIBE, DISCONNECT, HEARTBEAT).permitAll()
.simpDestMatchers("/app/**", "/topic/**").authenticated().simpSubscribeDestMatchers("/topic/**").authenticated()
.anyMessage().denyAll();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
关于使用 Spring Security 和 Keycloak 进行 Spring Websockets 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50573461/
我已将 Keycloak 设置为 SAML 代理,身份验证由当局提供的外部 IdP 完成。使用此 IdP 登录的用户都被接受,我们需要从 Keycloak 获得一个 OAuth token 来访问我们
我在 master 有一个服务帐号领域。来自 admin-cli我要分配服务帐号master-realm-client管理员角色。我怎样才能做到这一点。 kcadm.sh add-roles -r m
在 Keycloak 中,是否可以对同一领域中的所有客户端仅进行一次登录?我已经以这种方式配置了服务器(从管理控制台): - 创建一个新领域(我们称之为 MyRealm); - 创建两个不同的客户端(
我们的团队正在开发一个集成到 Keycloak 中的项目。我们创建了一个自定义领域,例如 ProjectX ,并使其上的自定义主题能够应用于 Keycloak 的登录页面。 由于我们的主题应用于领域
Keycloak 是一个很棒的工具,但它缺乏适当的文档。 所以我们有 Realm.roles、Client.roles 和 User.roles 使用特定客户端访问应用程序时,这 3 者如何协同工作?
我们的团队正在开发一个集成到 Keycloak 中的项目。我们创建了一个自定义领域,例如 ProjectX ,并使其上的自定义主题能够应用于 Keycloak 的登录页面。 由于我们的主题应用于领域
有没有办法让所有用户在 keycloak 中创建自定义用户属性(如电话号码)? 最佳答案 您可以创建一个组并向其添加一个属性。 然后将该组设置为默认组。这样,所有用户都可以使用设置为组的属性 关于ke
我还尝试了 Web 来源和有效重定向 URI 的所有不同组合 我通过 keycloak 登录,它不断地在我的本地主机应用程序和这个 url 之间来回重定向我:http://localhost:4200
在 Keycloak's documentation ,据说为了部署提供程序,我可以 copy your provider jar to the Keycloak deploy/ directory,
目前,我使用此端点一次将用户添加到一个组: PUT /{realm}/users/{id}/groups/{groupId} 在我的用例中,批量执行影响是有益的,到目前为止我还没有找到这样做的记录方式
目前,我使用此端点一次将用户添加到一个组: PUT /{realm}/users/{id}/groups/{groupId} 在我的用例中,批量执行影响是有益的,到目前为止我还没有找到这样做的记录方式
我一直在尝试在 docker-compose 文件中使用 jboss/keycloak-mysql 来建立 Keycloak 服务器和 mysql 数据库。我在本地部署期间遇到一个问题,告诉我 WEB
我正在使用 Tomcat 适配器运行 Keycloak。但是,当我尝试获取 KeycloakPrincipal 时,它出错了; java.lang.ClassCastException: org.ke
我正在使用 keycloak 4.5.0 v 并创建了一个领域。我已经设置了登录以启用忘记用户名和验证电子邮件。在我输入的电子邮件选项卡中 host - smtp.gmail.com smtp po
我想让我的客户端应用程序从 keycloak 访问用户信息。因此,我在 keycloak 中创建了另一个领域 (myrealm1),并在该领域内创建了一个新客户端 (myclient1)。 key 斗
正如我在此链接中看到的 https://www.keycloak.org/docs/latest/authorization_services/#_overview ,客户端中应该有一个授权选项卡,如
这些 keycloak 端点有什么用? issuer: "http://localhost:8180/auth/realms/dev", authorization_endpoint: "http:/
我们需要将数百个用户从 csv 文件导入 Keycloak。我还没有找到任何现成的导入功能来做到这一点。 有没有人做过任何导入程序或至少有一些框架来构建? REST API 可能是唯一的方法 - 或者
我已经使用 LDAP 用户联盟配置了 Keycloak。当用户想要登录应用程序时,他会被重定向到 Keycloak 登录页面,输入 uid/pwd 并使用 LDAP 绑定(bind)进行身份验证。 这
有没有人在 Keycloak 中使用过 SCIM?如果是这样,你能指出我的文档吗?我用谷歌搜索过,它似乎不是受支持的配置。 最佳答案 不幸的是,Keycloak 尚不支持 SCIM。他们的 Jira
我是一名优秀的程序员,十分优秀!