Keycloak and spring boot rest api - user specific data stragegy

心不动则不痛 提交于 2019-12-08 01:33:25

We have a similar requirement in a Java EE application, where a user can create data via a JSF website. Data is stored to postrgesql with audit information (username, userid, timestamps,...) so exactly what you want to achieve I suppose.

We have implemented by simply retrieving the information via the access token that is currently available in the session. We also introduced a new user attribute in keycloak itself, which is a custom account id. The user sets it on keycloak GUI and we retrieve it via accessToken.getOtherClaims().get("ACCOUNT_ID") to query user specific data.

The token itself is handled in a filter and used in another bean to retrieve the data which looks like

@WebFilter(value = "/*")
public class RefreshTokenFilter implements Filter {

  @Inject
  private ServletOAuthClient oauthClient;

  @Inject
  private UserData userData;
  @Context
  KeycloakSecurityContext  sc;

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    if (request.getUserPrincipal() != null) {
      KeycloakSecurityContext keycloakSecurityContext = ((KeycloakPrincipal) request.getUserPrincipal()).getKeycloakSecurityContext();
      userData.setAccessToken(keycloakSecurityContext.getToken());
      userData.setIdToken(keycloakSecurityContext.getIdToken());
    }
    filterChain.doFilter(request, response);
  }

  @Override
  public void destroy() {
  }
}

and here I have the bean that handles the data access

@SessionScoped
@Named("userData")
public class UserData implements Serializable {

  private static final String ACCOUNT_ID = "accountId";
  private AccessToken accessToken;
  private IDToken idToken;

  public String getUserFullName() {
    return isHasAccessToken() ? accessToken.getName() : null;
  }

  public String getUserName() {
    return isHasAccessToken() ? accessToken.getPreferredUsername() : null;
  }

  public String getUserId() {
    return isHasAccessToken() ? accessToken.getSubject() : null;
  }

  public String getRoles() {
    StringBuilder roles = new StringBuilder();
    if (isHasAccessToken()) {
      accessToken.getRealmAccess().getRoles().stream().forEach(s -> roles.append(s).append(" "));
    }
    return roles.toString();
  }

  public boolean hasApplicationRole(String role) {
    return accessToken.getRealmAccess().isUserInRole(role);
  }

  public boolean isHasAccessToken() {
    return accessToken != null;
  }

  public List<String> getAccountIds() {
    return isHasAccessToken() && accessToken.getOtherClaims().get(ACCOUNT_ID)!=null ? (List<String>) accessToken.getOtherClaims().get(ACCOUNT_ID) : new ArrayList<>();
  }

  public void setAccessToken(AccessToken accessToken) {
    this.accessToken = accessToken;
  }

  public void setIdToken(IDToken idToken) {
    this.idToken = idToken;
  }
}

I would assume spring boot will give you similar options to deal with the KeycloakSecurityContext.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!