如何将User对象放入UsernamePasswordAuthenticationToken(AuthenticationProvider)?

时间:2016-04-12 21:49:46

标签: java spring spring-mvc java-ee spring-security

当我尝试将当前User对象放入CustomAuthenticationProvider返回的UsernamePasswordAuthenticationToken时,我遇到了一些问题。 所以在开始时我需要显示我的spring-security.xml,它看起来像这样:

    <http auto-config="true" use-expressions="true">
    <intercept-url pattern="/sign/in" access="isAnonymous()" /> 
    <intercept-url pattern="/sign/up" access="isAnonymous()" /> 
    <intercept-url pattern="/secret/page" access="isAuthenticated()" />
    <intercept-url pattern="/sign/out" access="isAuthenticated()" />
    <intercept-url pattern="/user/myinfo" access="isAuthenticated()" />

    <form-login
        login-page="/sign/in"
        default-target-url="/secret/page"
        authentication-failure-url="/sign/in?failed=1"
        password-parameter="password"
        username-parameter="email"
    />
    <csrf disabled="true"/>
    <logout
        logout-url="/sign/out"
    />

    </http>
    <authentication-manager erase-credentials="false">
    <authentication-provider ref="customAuth">
    </authentication-provider>
    </authentication-manager>

    <beans:bean id="customAuth" class="milkiv.easyword.controller.sign.CustomAuthenticationProvider"/>

我有输入我的电子邮件和密码的页面/ sign / in以登录。所以使用AuthenticationProvider的下一个代码我总是被重定向到我定义为login-page =“/ sign / in的页面“(不是故障 - 网址,我已经检查过了)。顺便说一句,如果只用Username而不是User对象,它就可以了。因此我的AuthenticationProvider代码是下一个:

@Service(value = "customAuth")
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    public Storages storage;

    @Override
    @Transactional
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String login = authentication.getName();
    String password = authentication.getCredentials().toString();
    User user = storage.uSM.findByEmailAndPassword(login, password);
    if (user == null) {
        return null;
    } else {
        // if to pur here login insted of user it works fine
        return new UsernamePasswordAuthenticationToken(user, password);
    }
    }

    @Override
    public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

有趣的是,在我的测试中,看起来:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:resources/spring-context.xml", "classpath:resources/spring-security.xml"})
@WebAppConfiguration
public class InTest {

    MockMvc mockMvc;

    Storages storages;

    @Autowired
    private Filter springSecurityFilterChain;

    private final String nickname = "LoremIpsum";
    private final String email = "lorem@ipsum.com";
    private final String password = "loreamipsumpassword";

    @Autowired
    WebApplicationContext wac; // cached

    @Before
    public void doBeforeTests() {
    mockMvc = MockMvcBuilders
        .webAppContextSetup(wac)
        .addFilters(springSecurityFilterChain)
        .build();
    ApplicationContext context = new ClassPathXmlApplicationContext("resources/spring-context.xml", "resources/spring-security.xml");
    storages = context.getBean(Storages.class);
    }

    @Test
    public void testSignIn() throws Exception {
    mockMvc.perform(
        formLogin()
            .user("email", email)
            .password(password)
    )
        .andExpect(redirectedUrl("/secret/page"));

} }

.andExpectFunction(redirectedUrl(“/ secret / page”))说我已经被重定向到default-target-url =“/ secret / page”,所以在那之后出现问题。 正如我读过AuthenticationProvider以某种方式使用AuthenticatioManager,可能问题出在这里? 有人可以解释我的错误,或者帮助弄清楚发生了什么,或者提供一些帮助我理解的链接,或其他什么。我将不胜感激任何帮助。 提前谢谢大家。

添加 用户模型:

public class User {
    private int userId;

    @NotBlank (message = "Email field can not be empty or missed")
    @Size(min = 5, max = 128, message = "Email field must have from 5 to 128 symbols")
    @Email(message = "Email field must have email format.")
    private String email;

    @NotBlank (message = "Password field can not be empty or missed")
    @Size (min = 5, max = 32, message = "Password field must have from 5 to 32 symbols")
    private String password;

    @NotBlank (message = "Confirm password field can not be empty or missed")
    @Size (min = 5, max = 32, message = "Confirm password field must have from 5 to 32 symbols")
    private String confirmPassword;

    @NotBlank (message = "Nickname field can not be empty or missed")
    @Size (min = 3, max = 32, message = "Nickname field must have from 3 to 32 symbols")
    private String nickname; 


    private Date registrationDate;

    private Set studyLanguages;

    public User(){
    }

    public int getUserId() {
    return userId;
    }

    public void setUserId(int userId) {
    this.userId = userId;
    }

    public String getEmail() {
    return email;
    }

    public void setEmail(String email) {
    this.email = email;
    }

    public String getPassword() {
    return password;
    }

    public void setPassword(String password) {
    this.password = password;
    }

    public String getNickname() {
    return nickname;
    }

    public void setNickname(String nickname) {
    this.nickname = nickname;
    }

    public Date getRegistrationDate() {
    return registrationDate;
    }

    public void setRegistrationDate(Date registration_date) {
    this.registrationDate = registration_date;
    }

    public Set getStudyLanguages() {
    return studyLanguages;
    }

    public void setStudyLanguages(Set studyLanguages) {
    this.studyLanguages = studyLanguages;
    }


    public String getConfirmPassword() {
    return confirmPassword;
    }

    public void setConfirmPassword(String confirmPassword) {
    this.confirmPassword = confirmPassword;
    }
}

1 个答案:

答案 0 :(得分:1)

我认为问题是你使用的是UsernamePasswordAuthenticationToken(用户,密码)的错误方法。方法UsernamePasswordAuthenticationToken 等待两个参数:一个主体(通常是一个字符串用户名)和一个密码。

通过从Authentification object获取它们,你做得很好但是用户对象不被视为主体,登录是。

    @Service(value = "customAuth")
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    public Storages storage;

    @Override
    @Transactional
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String login = authentication.getName();
    String password = authentication.getCredentials().toString();
    User user = storage.uSM.findByEmailAndPassword(login, password);
    if (user == null) {
        return null;
    } else {
        // Here use the user object to only check if the user exists in the database if not null use his login ( principal ) and password
        return new UsernamePasswordAuthenticationToken(login, password);
    }
    }

    @Override
    public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

其他一些资源:

这是一个link,你可以在这里用你的用户对象做同样的事情。您将使用UserDetailsUserDetails