跟着JHipster学做项目 (16) Spring Boot在JWT添加userId

22 篇文章 14 订阅
4 篇文章 0 订阅

Spring boot默认User没有包含userId信息,在通过SecurityUtils获取userId会很不方便,下面介绍一个简便的方式可以在获取当前用户信息时,能够包含userId。

JHipster是通过一个实现UserDetailService的接口DomainUserDetailsService类,来对登录信息进行认证。

但是在类UserJWTController中,认证的方法如下:

Authentication authentication = authenticationManagerBuilder.getObject()
.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);

在获取Authentication的同时,把它放入SecurityContextHolder的上下文。也就是说,我们需要在authentication中包含userId信息,那么这里的authenticate方法是如何关联DomainUserDetailsService中的loadUserByUsername方法呢?

JHipster并没有做任何处理,只是利用了spring boot的默认配置,我们来看一下security部分的autoconfiguration。

在org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration类中,initializeUserDetailsBeanManagerConfigurer方法创建了一个InitializeUserDetailsBeanManagerConfigurer类,该类的configure(AuthenticationManagerBuilder auth)方法将UserDetailsService赋给了DaoAuthenticationProvider。

	class InitializeUserDetailsManagerConfigurer
			extends GlobalAuthenticationConfigurerAdapter {
		@Override
		public void configure(AuthenticationManagerBuilder auth) throws Exception {
			if (auth.isConfigured()) {
				return;
			}
			UserDetailsService userDetailsService = getBeanOrNull(
					UserDetailsService.class);
			if (userDetailsService == null) {
				return;
			}

			PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
			UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);

			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
			provider.setUserDetailsService(userDetailsService);
			if (passwordEncoder != null) {
				provider.setPasswordEncoder(passwordEncoder);
			}
			if (passwordManager != null) {
				provider.setUserDetailsPasswordService(passwordManager);
			}
			provider.afterPropertiesSet();

			auth.authenticationProvider(provider);
		}

这里我们只要记住DaoAuthenticationProvider包含了userDetailsService。

下面再找到authenticationManager和DaoAuthenticationProvider的关系:Provider可以看成等同于Manager类,它多了一个是否支持authentication的support方法,这样authenticationManager的authenticate方法和loadUserByUsername方法就关联到一起。

为了使authentication类中包含userId信息,

第一步,扩展org.springframework.security.core.userdetails.User类

public class AuthenticatedUser extends User {

	private String userId = "";
	public AuthenticatedUser(String userId, String username,
         String password, Collection<? extends GrantedAuthority> authorities) {
		super(username, password, authorities);
		this.userId = userId;
	}
    public String getUserId() {
        return this.userId;
    }
}

第二步,改变loadUserByUsername返回AuthenticatedUser类

	private AuthenticatedUser createSpringSecurityUser(ApplicationUser user) {

		List<GrantedAuthority> grantedAuthorities = 
            getAuthorities(user.toApplicationUserDto());

		return new AuthenticatedUser(user.getId(),
             user.getUserName(),user.getPassword(), grantedAuthorities);
	}

第三步,在TokenProvider中改变createToken和getAuthentication两个方法,添加userId信息

    public String createToken(Authentication authentication, boolean rememberMe) {
        String authorities = authentication.getAuthorities().stream()
            .map(GrantedAuthority::getAuthority)
            .collect(Collectors.joining(","));
        long now = (new Date()).getTime();
        Date validity;
        if (rememberMe) {
            validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
        } else {
            validity = new Date(now + this.tokenValidityInMilliseconds);
        }
        return Jwts.builder()
            .setSubject(authentication.getName())
            .claim(AUTHORITIES_KEY, authorities)
            .claim("userId", ((AuthenticatedUser)authentication.getPrincipal()).getUserId())
            .signWith(key, SignatureAlgorithm.HS512)
            .setExpiration(validity)
            .compact();
    }

    public Authentication getAuthentication(String token) {
        Claims claims = Jwts.parserBuilder().setSigningKey(key)
                .build()
                .parseClaimsJws(token)
            .getBody();
        Collection<? extends GrantedAuthority> authorities =
            Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        AuthenticatedUser principal = new AuthenticatedUser(claims.get("userId").toString(), claims.getSubject(), "", authorities);

        return new UsernamePasswordAuthenticationToken(principal, token, authorities);
    }

本文介绍是基于跟着JHipster学做项目 (6) 安全访问控制(上)JWT的Spring Boot应用

Good Luck,

Cheers!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值