Как получить информацию о пользователе в контроллере приложения Spring Boot OIDC?

Я адаптировал код из здесь для вызова сервера MitreID OIDC.

Мой контроллер:

    public final String home(Principal p) {
    final String username = SecurityContextHolder.getContext().getAuthentication().getName();
...

возвращает null и имеет значение null для всех сведений о пользователе.

Я также пробовал:

public final String home(@AuthenticationPrincipal OpenIdConnectUserDetails user) {
        final String username = user.getUsername();

а также

@RequestMapping(value = "/username", method = RequestMethod.GET)
    @ResponseBody
    public String currentUserNameSimple(HttpServletRequest request) {
        Principal principal = request.getUserPrincipal();
        return "username: " + principal.getName();
    }

Все пусто, но аутентификация является возвращает токен доступа и пользователя.

Моя конфигурация безопасности:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private OAuth2RestTemplate restTemplate;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Bean
    public OpenIdConnectFilter myFilter() {

        final OpenIdConnectFilter filter = new OpenIdConnectFilter("/openid_connect_login");
        filter.setRestTemplate(restTemplate);
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // @formatter:off
        http
        .addFilterAfter(new OAuth2ClientContextFilter(), AbstractPreAuthenticatedProcessingFilter.class)
        .addFilterAfter(myFilter(), OAuth2ClientContextFilter.class)
        .httpBasic().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/openid_connect_login"))
        .and()
        .authorizeRequests()
        .antMatchers("/","/index*").permitAll()
        .anyRequest().authenticated()
        ;

     // @formatter:on
    }
}

Так почему мой контроллер не может получить доступ к данным пользователя?

Обновлено: по запросу, OpenIdConnectFilter:

 package org.baeldung.security;

import java.io.IOException;
import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;

import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.UrlJwkProvider;
import com.fasterxml.jackson.databind.ObjectMapper;

public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
    @Value("${oidc.clientId}")
    private String clientId;

    @Value("${oidc.issuer}")
    private String issuer;

    @Value("${oidc.jwkUrl}")
    private String jwkUrl;

    public OAuth2RestOperations restTemplate;

    public OpenIdConnectFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
        setAuthenticationManager(new NoopAuthenticationManager());
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {

        OAuth2AccessToken accessToken;
        logger.info("ewd here: b " );
        try {
            accessToken = restTemplate.getAccessToken();
        } catch (final OAuth2Exception e) {
            throw new BadCredentialsException("Could not obtain access token", e);
        }
        try {
            logger.info("ewd access token: " + accessToken);
            final String idToken = accessToken.getAdditionalInformation().get("id_token").toString();
            String kid = JwtHelper.headers(idToken)
                .get("kid");
            final Jwt tokenDecoded = JwtHelper.decodeAndVerify(idToken, verifier(kid));
            final Map<String, String> authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
            verifyClaims(authInfo);
            final OpenIdConnectUserDetails user = new OpenIdConnectUserDetails(authInfo, accessToken);
            logger.info("ewd user token: " + tokenDecoded);
            return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        } catch (final Exception e) {
            throw new BadCredentialsException("Could not obtain user details from token", e);
        }

    }

    public void verifyClaims(Map claims) {
        int exp = (int) claims.get("exp");
        Date expireDate = new Date(exp * 1000L);
        Date now = new Date();
        if (expireDate.before(now) || !claims.get("iss").equals(issuer) || !claims.get("aud").equals(clientId)) {
            throw new RuntimeException("Invalid claims");
        }
    }


    private RsaVerifier verifier(String kid) throws Exception {
        JwkProvider provider = new UrlJwkProvider(new URL(jwkUrl));
        Jwk jwk = provider.get(kid);
        return new RsaVerifier((RSAPublicKey) jwk.getPublicKey());
    }

    public void setRestTemplate(OAuth2RestTemplate restTemplate2) {
        restTemplate = restTemplate2;

    }

    private static class NoopAuthenticationManager implements AuthenticationManager {

        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
        }

    }
}

Вы также можете предоставить свой класс OpenIdConnectFilter?

jrsall92 27.03.2019 17:42

Спасибо. Добавил.

schoon 27.03.2019 19:20

вы сюда заглядывали? github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server‌​/…

jrsall92 28.03.2019 10:51

Я не вижу URL-адрес настроенной информации о пользователе, который Spring может использовать для заполнения принципа. я ошибся?

stacker 29.03.2019 12:23
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
4
2 255
4

Ответы 4

В учебнике, на который вы ссылаетесь, используется Google OpenId Connect. Эта служба также возвращает переменную электронной почты дополнительной области действия, которая считывается в:

OpenIdConnectUserDetails.класс

    public OpenIdConnectUserDetails(Map<String, String> userInfo, OAuth2AccessToken token) {
        this.userId = userInfo.get("sub");
        this.username = userInfo.get("email");
        this.token = token;
    }

Не зная конкретной конфигурации вашего сервера MitreID OIDC, возможно, сервер openId не возвращает переменную электронной почты.

Спасибо, но он возвращается, но его не видно в контроллере.

schoon 01.04.2019 18:01

Я новый пользователь auth0, и у меня была такая же проблема, когда я пытался получить некоторую информацию о пользователе в контроллере Spring. Я могу получить доступ к претензиям из токена, используя этот код.

@GetMapping
public List<Task> getTasks(AuthenticationJsonWebToken authentication) {
    logger.debug("getTasks called.");
    DecodedJWT jwt = JWT.decode(authentication.getToken());
    Map<String, Claim> claims = jwt.getClaims();
    for (Object key: claims.keySet()) {
        logger.debug("key: {}, value: {}", key.toString(),  claims.get(key).asString());
    }

    return taskRepository.findAll();
}

Надеюсь это поможет.

Если вам нужно имя пользователя, вы можете получить его из объекта JwtAuthenticationToken, как показано ниже:

@GetMapping("/home")
public String home(JwtAuthenticationToken user) {
        String name = user.getName();

Если вам нужна какая-то другая информация из профиля пользователя, вы можете вызвать конечную точку /userinfo вашего сервера аутентификации с токеном доступа, как показано ниже: Это будет получать информацию только в том случае, если вы включили profile область действия в свой authorize вызов.

@GetMapping("/home")
public String home(JwtAuthenticationToken user) {

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.AUTHORIZATION, "Bearer "+user.getToken().getTokenValue());
        HttpEntity entity = new HttpEntity(headers);
        ResponseEntity<Map> userinfo = template.exchange("https://your-auth-server/default/v1/userinfo", HttpMethod.GET, entity, Map.class);
        String name = (String) userinfo.getBody().get("given_name");

Вы можете получить все атрибуты профиля из этого ответа.

Для Auth0 я смог получить информацию о пользователе двумя способами:

  1. Первый использует JwtAuthenticationToken непосредственно на контроллере, как показано ниже.

    @GetMapping("/Информация") публичные недействительные пользователи (токен JwtAuthenticationToken) { System.out.println(токен.getName()); System.out.println(token.getTokenAttributes().get("имя")); }

Здесь token.getName() печатает идентификатор пользователя из auth0, а token.getTokenAttributes() возвращает карту, из которой мы можем получить любую необходимую нам информацию. Например, чтобы напечатать имя пользователя, мы можем использовать token.getTokenAttributes().get("name").

  1. Приведение объекта Authentication к JwtAuthenticationToken:

    Аутентификация аутентификации = SecurityContextHolder.getContext().getAuthentication(); Токен JwtAuthenticationToken = (JwtAuthenticationToken) аутентификация;

    Строка имя пользователя = token.getTokenAttributes().get("имя");

нужно правильное оформление

Ajay Mistry 18.01.2022 15:46

Другие вопросы по теме