【问题标题】:Springboot get username from Authentication via ControllerSpring Boot通过Controller从Authentication获取用户名
【发布时间】:2018-09-06 20:36:24
【问题描述】:

问题: 我想仅从 authenticate.getName()... 获取/提取用户名/电子邮件,如果可能,而不是使用解析字符串。

authentication.getName() 或 principal.getName() 值:

[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

在本例中,我只想获取用户名的值,即 butitoy@iyotbihagay.com

解决方案:

由于我只想获取用户名/电子邮件 (butitoy@iyotbihagay.com),并且它返回整个主要内容/文本(上图),因此我将我在主题中设置的值替换为主要值.. . 到电子邮件值.. 它现在可以工作了。

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

我现在可以使用不同的方式获取用户名/电子邮件值,例如你们建议的方式……甚至是我目前使用的方式。我现在不需要任何特殊的解析来从 Authentication 对象中获取电子邮件值。

在我之前使用 Spring 的非 RESTful 应用程序中...我可以使用控制器方法参数中注入的 Authentication 类轻松获取用户名。

控制器:

...  
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]: butitoy@iyotbihagay.com

现在,在我当前的项目中……我使用了 RESTful 方法,在成功验证后,我返回了一个令牌,该令牌将在请求标头中使用/注入。我可以使用令牌登录...但是当我获得 authentication.getName() 的值时...返回的不仅仅是电子邮件地址,它还包含一些其他信息。

控制台(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

我只想获取用户名值“butitoy@iyotbihagay.com”。

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

}

【问题讨论】:

  • 为什么不在控制器中设置断点并检查 Authentication 对象的值?
  • 只是想指出,RESTful 与你是否使用 JWT 无关。
  • 感谢您的注意,顺便说一句,我是 REST 新手。我尝试调试控制器,但得到的是整个长字符串值,而不是分隔字符串。
  • 你得到了整个对象,因为这就是你传递给的内容:String token = Jwts.builder().setSubject(principal)。您可以将其更改为使用电子邮件,或者只使用用户名,然后稍后为该用户进行查找。
  • @BorgyManotoy 对此有何更新?

标签: java spring spring-boot spring-security jwt


【解决方案1】:

我认为您可以在AuthenticationPrincipal 类型的注入控制器参数中使用authentication.getNameprincipal.getName

@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:用户名:butitoy@iyotbihagay.com;密码保护];启用:真; AccountNonExpired:真;凭据非过期:真; AccountNonLocked:真;未授予任何权限
【解决方案2】:

就 Authentication/Principal 对象而言,使用令牌还是基本 spring 安全认证都没有关系。

在 Spring Security 的情况下,您可以通过
获取当前登录用户 1.Object user = Authentication authentication(正如你已经在做的那样)
2.

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

在这两种情况下,user 将包含您从UserDetailsService.loadUserByUsername(...) 返回的用户对象。所以使用默认的UserDetailsService,你会得到spring security的User对象,其中包含usernamepassword等基本用户信息。

因此,如果您使用默认 spring 的 UserDetailsService,那么您可以通过以下方式获取当前登录用户

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

【讨论】:

  • 无法投射到用户
【解决方案3】:

你可以使用

导入 org.springframework.security.core.Authentication;

导入 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】:

    到目前为止还没有看到任何公认的答案,也许这会有所帮助:

    使用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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-12
      • 2018-09-08
      • 2018-01-13
      • 2018-10-25
      • 2017-12-22
      • 2019-06-19
      • 1970-01-01
      • 2017-07-15
      相关资源
      最近更新 更多