Springboot получает имя пользователя из аутентификации через контроллер

Проблема: Я хотел бы получить / извлечь имя пользователя / адрес электронной почты только из Authenticate.getName () ... если возможно, не используя синтаксический анализ строки.

Значения authentication.getName () или Principal.getName ():

[username]: org.springframework.security.core.userdetails.User@21463e7a: Username: [email protected]; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities

В этом примере я хотел бы получить только значение имени пользователя, которое является [email protected].

Решение:

Поскольку я хочу получить только имя пользователя / адрес электронной почты ([email protected]), и он возвращает весь основной контент / текст (см. Выше), я заменил значение, которое я установил в теме, с основного значения ... на значение электронной почты .. и теперь он работает.

@Override
protected void successfulAuthentication(HttpServletRequest req,
                                        HttpServletResponse res,
                                        FilterChain chain,
                                        Authentication auth) throws IOException, ServletException {
    String email = auth.getName();
    String principal = auth.getPrincipal().toString();
    Date expiration = new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME);
    String token = Jwts.builder()
            .setSubject(email) //from principal to email
            .setExpiration(expiration)
            .signWith(SignatureAlgorithm.HS512, SecurityConstants.SECRET.getBytes())
            .compact();
    AuthenticatedUser loginUser = new AuthenticatedUser(email);
    loginUser.setToken(token);
    String jsonUser = Util.objectToJsonResponseAsString(loginUser, "user");
    res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
    res.setContentType("application/json");
    res.setCharacterEncoding(ConstantUtil.DEFAULT_ENCODING);
    res.getWriter().write(jsonUser);
}

Теперь я могу получить имя пользователя / адрес электронной почты, используя разные способы, такие как тот, который вы предлагаете ... даже тот, который я использую в настоящее время. Мне не нужен сейчас какой-либо специальный синтаксический анализ, чтобы получить значение электронной почты из объекта аутентификации.

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

Контроллер:

...  
public Ticket getBySwertresNo(Authentication authentication, @PathVariable String swertresNo) {  
    logger.debug("Inside getBySwertresNo: " + swertresNo);  
    System.out.println("\n[username]: " + authentication.getName() + "\n");  
    return m_sugalService.getSwertresInfoBySwertresNo(swertresNo);  
}  
...  

Приставка:

[username]: [email protected]

Теперь, в моем текущем проекте ... Я использовал подход RESTful, и после успешной аутентификации я возвращаю токен, который будет использоваться / вводиться в заголовок запроса. Я могу войти в систему, используя токен ... но когда я получаю значение authentication.getName () ... возвращается не только адрес электронной почты, но и некоторая другая информация.

Консоль (REST + JWT):

[username]: org.springframework.security.core.userdetails.User@21463e7a: Username: [email protected]; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities

Я хотел бы получить только значение имени пользователя: «[email protected]».

Фильтр аутентификации JWT:

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req,
                                                HttpServletResponse res) throws AuthenticationException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        return authentication;
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req,
                                            HttpServletResponse res,
                                            FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        String email = auth.getName();
        String principal = auth.getPrincipal().toString();
        Date expiration = new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME);
        String token = Jwts.builder()
                .setSubject(principal)
                .setExpiration(expiration)
                .signWith(SignatureAlgorithm.HS512, SecurityConstants.SECRET.getBytes())
                .compact();
        AuthenticatedUser loginUser = new AuthenticatedUser(email);
        loginUser.setToken(token);
        String jsonUser = Util.objectToJsonResponseAsString(loginUser, "user");
        res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
        res.setContentType("application/json");
        res.setCharacterEncoding(ConstantUtil.DEFAULT_ENCODING);
        res.getWriter().write(jsonUser);
    }

}

Фильтр авторизации JWT:

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    public JWTAuthorizationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                    HttpServletResponse res,
                                    FilterChain chain) throws IOException, ServletException {
        String header = req.getHeader(SecurityConstants.HEADER_STRING);

        if (header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            chain.doFilter(req, res);
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);

SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(SecurityConstants.HEADER_STRING);
        if (token != null) {
            // parse the token.
            String user = Jwts.parser()
                    .setSigningKey(SecurityConstants.SECRET.getBytes())
                    .parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, ""))
                    .getBody()
                    .getSubject();

            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }

}

почему бы вам не поставить точку останова в вашем контроллере и не проверить значение объекта аутентификации?

Tino M Thomas 28.03.2018 10:45

Просто хотел отметить, что RESTfulness не имеет ничего общего с тем, используете ли вы JWT или нет.

kaqqao 28.03.2018 11:09

Спасибо за заметку, я новичок в REST, кстати. Я попытался отладить контроллер, но получаю все длинное строковое значение, а не отдельные строки.

Borgy Manotoy 28.03.2018 11:24

вы получаете весь объект, потому что это то, что вы передаете в: String token = Jwts.builder (). setSubject (Principal). Вы можете изменить это, чтобы использовать электронную почту, или просто введите имя пользователя, а затем выполните поиск этого пользователя позже.

steve 22.05.2018 06:31

@BorgyManotoy Есть какие-нибудь обновления для этого?

Edwin Diaz 08.01.2019 18:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
5
34 967
4

Ответы 4

Что касается объекта Authentication / Principal, не имеет значения, используете ли вы токен или базовую проверку подлинности Spring Security.

В случае весенней безопасности вы можете получить текущего авторизованного пользователя по
. 1. Object user = Authentication authentication (как вы уже делаете)
2.

Object user = SecurityContextHolder.getContext().getAuthentication()
                    .getPrincipal();

В обоих случаях user будет содержать объект пользователя, возвращаемый вами из UserDetailsService.loadUserByUsername(...). Таким образом, используя UserDetailsService по умолчанию, вы получите объект Spring Security User, который содержит основную информацию о пользователе, такую ​​как username, password и т. д.

Так что, если вы используете Spring UserDetailsService по умолчанию, вы можете получить текущего пользователя, вошедшего в систему, просто с помощью

UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication()
                        .getPrincipal();
String username = userDetails.getUsername();

Невозможно передать пользователю

Borgy Manotoy 28.03.2018 14:52

Я думаю, вы можете использовать authentication.getName и principal.getName во введенном аргументе контроллера типа Authentication и Principal:

@Controller
@RequestMapping("/info")
public class GetNameController {

    @RequestMapping(value = "/name", method = RequestMethod.GET)
    public String getName(Authentication authentication, Principal principal) {
        System.out.println(authentication.getName());
        System.out.println("-----------------");
        System.out.println(principal.getName());
        return "";
    }
}

мог произвести

admin
-----------------
admin

Те же результаты: org.springframework.security.core.userdetails.User@21463e7a: Имя пользователя: [email protected]; Пароль защищен]; Включено: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Не предоставлено никаких полномочий

Borgy Manotoy 28.03.2018 14:52

Ты можешь использовать

import org.springframework.security.core.Authentication;

import org.springframework.security.core.context.SecurityContextHolder;

Authentication auth = SecurityContextHolder.getContext().getAuthentication();



   System.out.println("--------------------------------------------------------------");
    JwtUser jwtUser = (JwtUser) auth.getPrincipal();
    
    //Get the username of the logged in user: getPrincipal()
    System.out.println("auth.getPrincipal()=>"+jwtUser.getUsername() );
    //Get the password of the authenticated user: getCredentials()
    System.out.println("auth.getCredentials()=>"+auth.getCredentials());
    //Get the assigned roles of the authenticated user: getAuthorities()
    System.out.println("auth.getAuthorities()=>"+auth.getAuthorities());
    //Get further details of the authenticated user: getDetails()
    System.out.println("auth.getDetails()=>"+auth.getDetails());
    System.out.println("--------------------------------------------------------------");

Пока не видел ни одного принятого ответа, возможно, это поможет:

используйте вызов JwtTokenUtils.debugPrint(); из класса ниже. Для другой полезной нагрузки токена посмотрите, что доступно внутри tokenMap.

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.*;

import static org.springframework.security.oauth2.provider.token.AccessTokenConverter.EXP;

public class JwtTokenUtils {

    private static final Logger logger = LoggerFactory.getLogger(JwtTokenUtils.class);
    private static Format dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static ObjectMapper objectMapper = new ObjectMapper();

    public static void debugPrint() {
        try {
            Map<String, Object>  tokenMap = decode(getToken());
            logger.debug("JwtTokenUtils:debugPrint jwt:"
                    + " user_name {" + tokenMap.get("user_name")
                    + "}, expired {" + convertTime((long)tokenMap.get(EXP))
                    + "}");
        } catch (Exception e) {
            logger.error("JwtTokenUtils:debugPrint exception: " + e);
        }
    }

    private static String getToken() {
        return getAuthorizationHeader().split(" ")[1];
    }

    private static String getAuthorizationHeader() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        return request.getHeader("Authorization");
    }

    private static Map<String, Object> decode(String token) {
        try {
            Jwt jwt = JwtHelper.decode(token);
            String claimsStr = jwt.getClaims();
            TypeReference<HashMap<String,Object>> typeRef = new TypeReference<>() {};
            return objectMapper.readValue(claimsStr, typeRef); 
        }
        catch (Exception e) {
            throw new InvalidTokenException("Cannot convert access token to JSON", e);
        }
    }

    private static String convertTime(long time){
        Date date = new Date(time * 1000);
        return dateFormat.format(date);
    }
}

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