带有附加自定义参数的 Spring Boot 身份验证

Springboot authentication with an additional custom parameter

我正在尝试在我的应用程序中使用 spring 启动安全。我需要同时访问销售人员和客户。每个都映射到不同的实体,进而使用不同的存储库。

我的 UserDetailServive 实现如何根据自定义表单参数使用不同的存储库?

<form th:action="@{/login}" method="post">
    <div>
        <label>User Name: <input type="text" name="username"/></label>
        <label>Password: <input type="password" name="password"/></label>
        <label>User type: <input type="radio" name="userType" value="customer"/>
                          <input type="radio" name="userType" value="salesMen"/></label>
    </div>
    <div><input type="submit" value="Login"/></div>
</form>

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    SalesMenRepository salesMenRepository;

    @Autowired
    CustomersRepository customersRepository;    


    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

        // How can I get userType parameter ????

        if ("salesMen".equals(userType)) {
            Optional<SalesMan> salesMan = salesMenRepository.findById(userName);
            if (!salesMan.isPresent()) {
                throw new UsernameNotFoundException(userName);
            }

            return new UserDetailsImp(salesMan.get());
        } else {
            Optional<Customer> customer = customersRepository.findById(userName);
            if (!customer.isPresent()) {
                throw new UsernameNotFoundException(userName);
            }

            return new UserDetailsImp(customer.get());      
        }
    }

}   

您可以用任何字符连接 userNameuserType,例如冒号: userName:userType,在loadUserByUsername方法中,你拆分得到 String[] parts = userName.split(":");
但是,当您将自定义参数加入用户名时,您必须自定义身份验证过滤器。在我的例子中,我添加了名称为 dmBhxhId 的新自定义参数。我创建 CustomUser:

public class CustomUser extends User {
    private Long dmBhxhId;

    public Long getDmBhxhId() {
        return dmBhxhId;
    }

    public void setDmBhxhId(Long dmBhxhId) {
        this.dmBhxhId = dmBhxhId;
    }

    public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities,
            Long dmBhxhId) {
        super(username, password, authorities);
        this.dmBhxhId = dmBhxhId;
    }

    public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }

}

我自定义身份验证过滤器

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private String extraParameter = "extra";
    private String delimiter = ":";

    /**
     * Given an {@link HttpServletRequest}, this method extracts the username
     * and the extra input values and returns a combined username string of
     * those values separated by the delimiter string.
     *
     * @param request
     *            The {@link HttpServletRequest} containing the HTTP request
     *            variables from which the username client domain values can be
     *            extracted
     */
    @Override
    protected String obtainUsername(HttpServletRequest request) {
        String username = request.getParameter(getUsernameParameter());
        String extraInput = request.getParameter(getExtraParameter());
        Map<String, String[]> map = request.getParameterMap();
        String combinedUsername = username + getDelimiter() + extraInput;
        return combinedUsername;
    }

    /**
     * @return The parameter name which will be used to obtain the extra input
     *         from the login request
     */
    public String getExtraParameter() {
        return this.extraParameter;
    }

    /**
     * @param extraParameter
     *            The parameter name which will be used to obtain the extra
     *            input from the login request
     */
    public void setExtraParameter(String extraParameter) {
        this.extraParameter = extraParameter;
    }

    /**
     * @return The delimiter string used to separate the username and extra
     *         input values in the string returned by
     *         <code>obtainUsername()</code>
     */
    public String getDelimiter() {
        return this.delimiter;
    }

    /**
     * @param delimiter
     *            The delimiter string used to separate the username and extra
     *            input values in the string returned by
     *            <code>obtainUsername()</code>
     */
    public void setDelimiter(String delimiter) {
        this.delimiter = delimiter;
    }
}

在 SecurityConfiguration 文件中,我初始化了 CustomAuthenticationFilter

 @Bean  
    public CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter bcsAuthFilter = new CustomAuthenticationFilter();
        bcsAuthFilter.setAuthenticationManager(authenticationManager());
        bcsAuthFilter.setAuthenticationFailureHandler(ajaxAuthenticationFailureHandler);
        bcsAuthFilter.setAuthenticationSuccessHandler(ajaxAuthenticationSuccessHandler);
        bcsAuthFilter.setFilterProcessesUrl("/api/authentication");
        bcsAuthFilter.setPostOnly(true);
        bcsAuthFilter.setExtraParameter("dm_bhxh_id");
        bcsAuthFilter.setUsernameParameter("j_username");
        bcsAuthFilter.setPasswordParameter("j_password");
        return bcsAuthFilter;
    } 

并在配置方法中调用

.addFilterBefore(bcsAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)

看起来像

    @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .csrf()
                .ignoringAntMatchers("/websocket/**").ignoringAntMatchers("/api/public/odts/**")
            .and()
                .addFilterBefore(bcsAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
....

完成,希望对您有所帮助! 对不起,我的英文不好。