Springboot get username from Authentication via Co

2019-06-07 04:04发布

问题:

Problem: I would like to get/extract the username/email only from authenticate.getName()... if possible, not by using parsing the string.

authentication.getName() or principal.getName() values:

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

In this example, I would like to get only the value of Username which is butitoy@iyotbihagay.com

Solution:

Since I only want to get the username/email (butitoy@iyotbihagay.com), and it is returning the whole principal content/text (above), I replaced the value I set in the subject from the pricipal value... to the email value.. and it works now.

@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);
}

I can now get the username/email value using different ways like the one you guys are suggesting... even the one I am currently using. I do not need any special parsing now just to get the email value from the Authentication object.

On my previous non RESTful application using Spring... I can easily get the username using Authentication class injected in the controller method parameter.

Controller:

...  
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);  
}  
...  

Console:

[username]: butitoy@iyotbihagay.com

Now, on my current project... I used a RESTful approach and after successful authentication, I am returning a token which will be used/injected in the request header. I can login using the token... but when I get the value of authentication.getName()... the return is not just the email address but it contains some other information.

Console (REST + JWT):

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

I would like to get only the username value which is "butitoy@iyotbihagay.com".

JWT Authentication Filter:

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 Authorization Filter:

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;
    }

}

回答1:

I think you can use authentication.getName and principal.getName in the injected controller argument of type Authentication and 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 "";
    }
}

could produce

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


回答2:

It doesn't matter whether you are using token or basic spring security authentication as far as Authentication/Principal object is concerned.

In case of spring security, you can get your current logged in user by
1. Object user = Authentication authentication (as you are already doing)
2.

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

In both cases, user will contains the user object you returning from UserDetailsService.loadUserByUsername(...). So using default UserDetailsService you will get spring security's User object which contains basic user information like username, password etc.

So in case if you are using default spring's UserDetailsService, then you can get your current logged in user simply by

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


回答3:

You can use

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("--------------------------------------------------------------");


回答4:

Have not seen so far any accepted answer, maybe this will help:

use JwtTokenUtils.debugPrint(); call from below class. For other token payload see what is available inside 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);
    }
}