【问题标题】:authentication failing in spring security, why?春季安全认证失败,为什么?
【发布时间】:2015-12-01 03:39:34
【问题描述】:

具有 Spring Security 的 Spring MVC 应用程序具有三个视图,包括主要公共站点 /、仅适用于登录用户的安全站点 /secure-home 和登录页面 /login。当所有用户尝试加载 /secure-home url 时,Spring 安全性成功地将所有用户重定向到 /login 页面。但问题在于,在自定义登录页面中输入有效凭据的用户不被允许查看/secure-home url。如何更改代码,以便使用有效凭据登录的用户被重定向到 /secure-home url?

请注意,login 页面不会在用户提交错误凭据时显示错误消息,即使下面的 jsp 代码应在身份验证失败时打印错误消息。

以下是代码的相关方面:

SecurityConfig.java 是:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/secure-home")
                .usernameParameter("j_username")
                .passwordParameter("j_password")
                .loginProcessingUrl("/j_spring_security_check")
                .failureUrl("/login")
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login")
                .and()
            .authorizeRequests()
                .antMatchers("/secure-home").hasAuthority("registered")
                .antMatchers("/j_spring_security_check").permitAll()
                .and()
            .userDetailsService(userDetailsService());
    }
}  

MessageWebApplicationInitializer.java 是:

@Order(2)
public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}

business-config.xml 包含:

<!-- lots of other stuff -->
<bean class="my.app.config.SecurityConfig"></bean>

mvc-core-config.java 包含:

<!--  lots of other stuff -->
<mvc:view-controller path="/" view-name="welcome" />
<mvc:view-controller path="/login" view-name="login" />

User.java 是:

@Entity
@Table(name="users")
public class User implements UserDetails{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Integer id;

    @Column(name= "email", unique=true, nullable=false)
    private String login;//must be a valid email address

    @Column(name = "password")
    private String password;

    @Column(name = "phone")
    private String phone;

    @Column(name = "pin")
    private String pin;

    @Column(name = "sessionid")
    private String sessionId;

    @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name="user_roles",
        joinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")},
        inverseJoinColumns = {@JoinColumn(name="role_id", referencedColumnName="id")}
    )
    private Set<Role> roles;

    public Integer getId() {return id;}
    public void setId(Integer id) { this.id = id;}

    public String getPhone(){return phone;}
    public void setPhone(String pn){phone = pn;}

    public String getPin(){return pin;}
    public void setPin(String pi){pin = pi;}

    public String getSessionId(){return sessionId;}
    public void setSessionId(String sd){sessionId = sd;}

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPassword() {
        return password;
    }

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

    //roles methods
    public void addRole(Role alg) {roles.add(alg);}
    public Set<Role> getRoles(){
        if(this.roles==null){this.roles = new HashSet<Role>();}
        return this.roles;
    }
    public void setRoles(Set<Role> alg){this.roles = alg;}
    public boolean isInRoles(int aid){
        ArrayList<Role> mylgs = new ArrayList<Role>();
        mylgs.addAll(this.roles);
        for(int a=0;a<mylgs.size();a++){if(mylgs.get(a).getId()==aid){return true;}}
        return false;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getUsername() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return false;
    }

}

Role.java 是:

@Entity
@Table(name="roles")
public class Role implements GrantedAuthority{

    @Id
    @GeneratedValue
    private Integer id;

    private String role;

    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "roles")
    private Set<User> userRoles;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public Set<User> getUserRoles() {
        return userRoles;
    }

    public void setUserRoles(Set<User> userRoles) {
        this.userRoles = userRoles;
    }

    @Override
    public String getAuthority() {
        // TODO Auto-generated method stub
        return null;
    }

}

用于填充数据库的DML 是:

SET FOREIGN_KEY_CHECKS=0;
INSERT INTO `roles` VALUES (100,'registered');
INSERT INTO `user_roles` VALUES (100,100);
INSERT INTO `users` VALUES (100,'user@domain.com','password','phonenumber','pin','sessionid');
SET FOREIGN_KEY_CHECKS=1;

login.jsp 是:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Custom Login page</title>
<style>.error {color: red;}
</style>

</head>
<body>
<div class="container">

<h1>Custom Login page</h1>
<p>
<c:if test="${error == true}">
    <b class="error">Invalid login or password.</b>
</c:if>
</p>

<form method="post" action="<c:url value='j_spring_security_check'/>" >
<table>
<tbody>
    <tr>
        <td>Login:</td>
        <td><input type="text" name="j_username" id="j_username"size="30" maxlength="40"  /></td>
    </tr>
    <tr>
        <td>Password:</td>
        <td><input type="password" name="j_password" id="j_password" size="30" maxlength="32" /></td>
    </tr>
    <tr>
    <td colspan=2>
          <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
    </td>
    </tr>
    <tr>
        <td></td>
        <td><input type="submit" value="Login" /></td>
    </tr>
</tbody>
</table>
</form> 
</div>
</body>
</html>

还有用于管理/secure-home url 模式的服务层、存储库层和控制器的代码。

【问题讨论】:

    标签: java spring spring-mvc spring-security


    【解决方案1】:

    /secure-home 仅适用于拥有registered 权限的用户。

    .antMatchers("/secure-home").hasAuthority("registered")
    

    而您的用户详细信息 User.java 总是返回 null 每当 spring security 检查经过身份验证的用户的权限时。

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return null;
    }
    

    试试这个

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for(Role role : roles){
            authorities.add(new SimpleGrantedAuthority(role.getRole()))
        }
        return authorities;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-04
      • 2014-10-08
      • 2015-11-05
      • 2013-05-28
      • 2013-12-22
      • 2014-02-02
      • 2012-12-13
      相关资源
      最近更新 更多