Spring Security自定义AuthenticationToken

时间:2019-04-25 07:16:52

标签: java spring spring-security

我实现自定义AuthenticationProvider并返回自定义AuthenticationToken

@Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        DBUser dbUser = userDao.getUserLDAP(username);
        //check password
        return new CustomAuthenticationToken(dbUser, password, grantedAuthorities);
    }

CustomAuthenticationToken:

public class CustomAuthenticationToken extends AbstractAuthenticationToken {
    private DBUser principal;
    private String credential;
    public CustomAuthenticationToken(DBUser dbUser, String password, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.setDetails(dbUser);
        this.principal = dbUser;
        this.credential = password;
        this.setAuthenticated(true);
    }
//getters, setters
}

但是当我尝试在控制器中做时:

@GetMapping("/user/current")
    public ResponseEntity<Object> currentUser(@AuthenticationPrincipal DBUser dbUser){
        return ResponseEntity.ok(dbUser);
    }

dbUser为空,因为方法AuthenticationPrincipalArgumentResolver中的resolveArguments

public Object resolveArgument(MethodParameter parameter, 
          ModelAndViewContainer mavContainer, NativeWebRequest 
          webRequest, WebDataBinderFactory binderFactory) throws 
     Exception {
        Authentication authentication = 
            SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return null;
        } else {
            Object principal = authentication.getPrincipal();

authentication.userAuthenticationUsernamePasswordAuthenticationToken的实例(不是我返回的自定义)。

如何放置令牌详细信息,然后从安全上下文中获取令牌?

我使用spring security oauth2 + jwt。

安全配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider authenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.NEVER);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

OAuth配置:

@Configuration
@EnableAuthorizationServer
public class OAuthConfig extends AuthorizationServerConfigurerAdapter {

    private static final String CLIENT_ID = "client";
    private static final String CLIENT_SECRET = "pwd";

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Bean
    public JwtAccessTokenConverter tokenEnhancer() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(Keys.PRIVATE_KEY);
        converter.setVerifierKey(Keys.PUBLIC_KEY);
        return converter;
    }

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(tokenEnhancer());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager)
                .tokenStore(tokenStore())
                .accessTokenConverter(tokenEnhancer());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient(CLIENT_ID)
                .secret(new BCryptPasswordEncoder().encode(CLIENT_SECRET))
                .scopes("read", "write")
                .authorizedGrantTypes("authorization_code", "refresh_token", "password")
                .scopes("openid")
                .autoApprove(true)
                .accessTokenValiditySeconds(20000)
                .refreshTokenValiditySeconds(20000);
    }
}

谢谢。

1 个答案:

答案 0 :(得分:0)

我通过向JWT添加手动附加信息来解决该问题

public class CustomJwtAccessTokenConverter extends JwtAccessTokenConverter {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        LinkedHashMap<String, Object> additionalInfo = new LinkedHashMap<>(accessToken.getAdditionalInformation());
        additionalInfo.put("details", authentication.getUserAuthentication().getDetails());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
        authentication.setDetails(authentication.getUserAuthentication().getDetails());
        return super.enhance(accessToken, authentication);
    }
}

JwtAccessTokenConverter的实现将我的详细信息放入令牌

在配置中:

@Bean
public JwtAccessTokenConverter tokenEnhancer() {
    JwtAccessTokenConverter converter = new CustomJwtAccessTokenConverter();
    converter.setSigningKey(Keys.PRIVATE_KEY);
    converter.setVerifierKey(Keys.PUBLIC_KEY);
    return converter;
}

@Bean
public JwtTokenStore tokenStore() {
    return new JwtTokenStore(tokenEnhancer());
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints.authenticationManager(authenticationManager)
            .tokenStore(tokenStore())
            .accessTokenConverter(tokenEnhancer());
}

在控制器中

@Autowired
    private TokenStore tokenStore;

    @GetMapping("/user/current")
    public ResponseEntity<Object> currentUser(OAuth2Authentication authentication) {
        OAuth2AuthenticationDetails auth2AuthenticationDetails = (OAuth2AuthenticationDetails) authentication.getDetails();
        Map<String, Object> details = tokenStore.readAccessToken(auth2AuthenticationDetails.getTokenValue()).getAdditionalInformation();
        return ResponseEntity.ok(details.get("details"));
    }