【问题标题】:Username and Password not mapping with Authentication in Spring用户名和密码未与 Spring 中的身份验证映射
【发布时间】:2017-01-09 04:31:17
【问题描述】:

我使用的是 Spring 4.3.1.RELEASE 版本,它是自定义身份验证登录应用程序。但是我遇到了问题

先看代码

CustomAuthenticationProvider.java

@Component
@Qualifier(value = "customAuthenticationProvider")
public class CustomAuthenticationProvider implements AuthenticationProvider{


public Authentication authenticate(Authentication authentication) throws     AuthenticationException {
    String username = authentication.getName();
    String password = (String) authentication.getCredentials();
    User user = new User();
    user.setUsername(username);
    user.setPassword(password);


    Role r = new Role();
    r.setName("ROLE_ADMIN");
    List<Role> roles = new ArrayList<Role>();
    roles.add(r);


    Collection<? extends GrantedAuthority> authorities = roles;
    return new UsernamePasswordAuthenticationToken(user, password, authorities);
}

public boolean supports(Class<?> arg0) {
    return true;
}

}

SecurityConfiguration.java

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;

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

//.csrf() is optional, enabled by default, if using     WebSecurityConfigurerAdapter constructor
@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
            .antMatchers("/admin/**").access("hasRole('ROLE_USER')")
            .and()
            .formLogin()
            .loginPage("/login").failureUrl("/login?error")
            .usernameParameter("username").passwordParameter("password")
            .and()
            .logout().logoutSuccessUrl("/login?logout")
            .and()
            .csrf();
}
}

login.jsp 这是我的登录页面

  <form name="loginForm" novalidate ng-submit="ctrl.login(user)">
        <div class="form-group" ng-class="{'has-error': loginForm.username.$invalid}">
            <input class="form-control" name="username" id="username"  type="text"
                   placeholder="Username" required ng-model="user.username" />
            <span class="help-block"
                  ng-show="loginForm.username.$error.required">Required</span>
        </div>
        <div class="form-group" ng-class="{'has-error': loginForm.password.$invalid}">
            <input class="form-control" name="password" id="password" type="password"
                   placeholder="Password" required ng-model="user.password" />
            <span class="help-block"
                  ng-show="loginForm.password.$error.required">Required</span>
        </div>
        <div class="form-group">
            <button type="submit" class="btn btn-primary pull-right"
                    value="Login" title="Login" ng-disabled="!loginForm.$valid">
                <span>Login</span>
            </button>
        </div>
    </form>

在 CustomAuhtenticationProvider 类中进行 authenticate()

  1. authentication.getCredentials();
  2. authentication.getName();

两者都给出空字符串,但我需要用户名和密码。

这是我的 AngularJS 服务

Service.js

  function loginUser(user) {
    var config = {
        headers: {
            'csrf_token': csrfToken
        }
    }


    var deferred = $q.defer();
    $http.post("/login", user,config)
        .then(
            function (response) {
                deferred.resolve(response.data);
            },
            function(errResponse){
                console.error('Error while creating User');
                deferred.reject(errResponse);
            }
        );
    return deferred.promise;
}

【问题讨论】:

  • 其实我用的是AngularJS,它包含在Service里面
  • 嗯...您如何发送用户名和密码?常见的表单参数或其他任何格式如json?
  • 我知道,这就是我告诉你尝试禁用 csrf() 的原因,因为表单中没有出现 csrf 令牌。正如@M.Deinum 所说,包括您的角度控制器或至少包含登录请求消息格式。我打赌你是以 json 格式发送的
  • AngularJS 默认为表单提交提供 json 格式。为什么你需要你自己的提供者,它甚至不做任何事情? bcz 我需要自己的身份验证,而不是 LDAP、DAO 或内存身份验证
  • 已经是@Naman

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


【解决方案1】:

您将身份验证凭据作为 JSON 发送,并且您正在使用默认 UsernamePasswordAuthenticationFilter 尝试从 HttpServletRequest 参数中检索身份验证凭据。

它们将始终为空。您必须构建自己的自定义过滤器,该过滤器从请求正文中收到的 json 而不是 http 参数中获取身份验证凭据。

看看this

编辑:事实是您没有获得从 Angular 控制器发送的登录凭据。原因可能是,如果您在请求正文中将它们作为 json 发送,则不能依赖默认的 UsernamePasswordAuthenticationFilter,因为它会尝试构建读取 HttpServletRequest 参数的 Authentication 对象。

公共类 UsernamePasswordAuthenticationFilter 扩展 AbstractAuthenticationProcessingFilter {

public Authentication attemptAuthentication(HttpServletRequest request,
            HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);
        ...
}

/**
     * Enables subclasses to override the composition of the password, such as by
     * including additional values and a separator.
     * <p>
     * This might be used for example if a postcode/zipcode was required in addition to
     * the password. A delimiter such as a pipe (|) should be used to separate the
     * password and extended value(s). The <code>AuthenticationDao</code> will need to
     * generate the expected password in a corresponding manner.
     * </p>
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the password that will be presented in the <code>Authentication</code>
     * request token to the <code>AuthenticationManager</code>
     */
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }

    /**
     * Enables subclasses to override the composition of the username, such as by
     * including additional values and a separator.
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the username that will be presented in the <code>Authentication</code>
     * request token to the <code>AuthenticationManager</code>
     */
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

您应该扩展此过滤器,覆盖尝试身份验证()方法以避免在恢复此凭据时调用获取用户名和获取密码。相反,编写一个自定义方法,您将在其中读取 ServletRequest's InputStream 并使用您以前使用的 json 库解析为对象。我一般用杰克逊this way

【讨论】:

  • 看一下附图;我没有得到空值,它是空字符串。
猜你喜欢
  • 2018-07-13
  • 2017-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多