简体   繁体   中英

Failed to instantiate org.springframework.security.authentication.UsernamePasswordAuthenticationToken using constructor NO_CONSTRUCTOR with arguments

I'm writing my own implementation of TokenStore ( org.springframework.security.oauth2.provider.token.TokenStore ) using MongoDB. To do that, I used the code of Iain Porter . I was able to persist the token in mongo.

I did it by Autowiring an instance of my custom TokenStore then I passed it to the endpoint. As such I'm able to login without any problem but I'm not able to retrieve the token from the mongo repository in the resource server.

My guess is that there is some problem with converting/mapping of the object in the database back to Java object that is the class is OAuth2AuthenticationReadConverter is not call an the appropriate time.

Please can somebody help in this task.

You need to create a converter and register it as Spring Mongo doesn't do this for you.

Create a converter

    package com.erranda.abraham.api.security;

import com.erranda.abraham.entity.Person;
import com.mongodb.DBObject;

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;

import java.util.*;

/**
 * @version 1.0
 * @author: Iain Porter
 * @since 23/05/2013
 */
//Hackery to deserialize back into an OAuth2Authentication Object made necessary because Spring Mongo can't map clientAuthentication to authorizationRequest
@ReadingConverter
@SuppressWarnings("rawtypes")
public class OAuth2AuthenticationReadConverter implements Converter<DBObject, OAuth2Authentication> {

    @Override
    @SuppressWarnings("unchecked")
    public OAuth2Authentication convert(DBObject source) {
        System.out.println(source);
        DBObject storedRequest = (DBObject)source.get("storedRequest");

        OAuth2Request oAuth2Request = new OAuth2Request((Map<String, String>)storedRequest.get("requestParameters"),
                (String)storedRequest.get("clientId"), null, true, new HashSet((List)storedRequest.get("scope")),
                null, null, null, null);
        DBObject userAuthorization = (DBObject)source.get("userAuthentication");
        Object principal = getPrincipalObject(userAuthorization.get("principal"));

        Authentication userAuthentication = new UsernamePasswordAuthenticationToken(principal,
                (String)userAuthorization.get("credentials"), getAuthorities((List) userAuthorization.get("authorities")));

        OAuth2Authentication authentication = new OAuth2Authentication(oAuth2Request,
                userAuthentication );
        return authentication;
    }

    private Object getPrincipalObject(Object principal) {
        if(principal instanceof DBObject) {
            DBObject principalDBObject = (DBObject)principal;
            Person user = new Person (principalDBObject);
            return user;
        } else {
            return principal;
        }
    }

    private Collection<GrantedAuthority> getAuthorities(List<Map<String, String>> authorities) {
        Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>(authorities.size());
        for(Map<String, String> authority : authorities) {
            grantedAuthorities.add(new SimpleGrantedAuthority(authority.get("role")));
        }
        return grantedAuthorities;
    }

}

Then you need to register converter along side your mongodb configuration

package com.erranda.abraham;

import com.erranda.abraham.api.security.OAuth2AuthenticationReadConverter;
import com.mongodb.Mongo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class MongoDbConfiguration extends AbstractMongoConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(MongoDbConfiguration.class);
    private static final String MONGO_DB_SERVER = "mongo.db.server";
    private static final String MONGO_DB_PORT = "mongo.db.port";
    private static final String MONGO_DB_NAME = "mongo.db.name";
    private static final String MONGO_DB_LOGON = "mongo.db.logon";
    private static final String MONGO_DB_PASSWORD = "mongo.db.password";
    private static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";

    @Autowired
    private ApplicationContext applicationContext;

    @Value("${" + MONGO_DB_SERVER + "}")
    private String mongoServer;
    @Value("${" + MONGO_DB_PORT + "}")
    private int mongoPort;
    @Value("${" + MONGO_DB_NAME + "}")
    private String mongoDBName;
    @Value("${" + MONGO_DB_LOGON + "}")
    private String mongoDbLogin;
    @Value("${" + MONGO_DB_PASSWORD + "}")
    private String mongoDbPassword;

    @Override
    protected String getDatabaseName() {
        return mongoDBName;
    }

    @Override
    @Bean
    public Mongo mongo() throws Exception {
        return new Mongo(mongoServer, mongoPort);
    }

    @Override
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        if (!StringUtils.isEmpty(mongoDbLogin)) {
            LOG.info("Configuring mongoTemplate with credentials.");
            MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo(), mongoDBName, new UserCredentials(mongoDbLogin, mongoDbPassword));
            return new MongoTemplate(mongoDbFactory, mappingMongoConverter());
        } else {
            LOG.info("Configuring mongoTemplate without credentials.");
            MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo(), mongoDBName);
            return new MongoTemplate(mongoDbFactory, mappingMongoConverter());
        }
    }


    @Override
    @Bean
    public CustomConversions customConversions() {
        List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
        OAuth2AuthenticationReadConverter converter = new OAuth2AuthenticationReadConverter();
        converterList.add(converter);
        return new CustomConversions(converterList);
    }



    private String getContextProperty(final String propertyKey) {
        return applicationContext.getEnvironment().getProperty(propertyKey);
    }
}

Don't forget to mark as correct if it works for you.

Based on https://github.com/iainporter/oauth2-provider

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM