【问题标题】:How to put User object into UsernamePasswordAuthenticationToken(AuthenticationProvider)?如何将用户对象放入 UsernamePasswordAuthenticationToken(AuthenticationProvider)?
【发布时间】:2016-08-03 17:46:59
【问题描述】:

当我尝试将当前用户对象放入由我的 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 的页面“(不是失败网址,我已经检查过了)。顺便说一句,如果把 User 对象而不是 Username 放在它工作正常。所以我的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;
    }
}

【问题讨论】:

  • 你能展示模型 User 的结构吗?该类是否实现了 toString() 类?
  • 不,它没有 toString() 实现......它是必需的吗?没看到...(我已经添加了用户模型代码。
  • 如果模型适合用作主体,最好拥有它。在这种情况下不是。

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


【解决方案1】:

我认为问题在于您以错误的方式使用 UsernamePasswordAuthenticationToken(user, password)。这里方法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

【讨论】:

  • 非常感谢您的解释。实际上,我知道我从一开始就选择了错误的方式,而不是通过 .addUserDetails 添加我的附加用户信息。
  • 我为您提供了一些额外的资源来尝试用好的“错误”方式来做到这一点。检查它们,我鼓励学习如何去做:)
猜你喜欢
  • 2011-12-31
  • 2016-04-07
  • 2014-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 2023-03-05
相关资源
最近更新 更多