首页 > 解决方案 > 使用 Java 注释配置的 Spring Security 配置错误

问题描述

早上好。

我有一个基于 Spring MVC 并由 Spring Security 保护的应用程序,特别是我正在使用这些版本:

主要问题

在使用基于 Java 的配置(注释)设置应用程序后,我正在测试登录请求是否得到正确处理,但我无法弄清楚为什么所有请求总是像循环一样被重定向到登录页面本身。

这是我第一次使用 Spring 安全性来保护 Web 应用程序,但我还没有找到任何答案。

我做了什么

MVC 部分在没有身份验证(甚至 JDBC 连接)的情况下运行良好,问题可能出在 Spring 安全性的配置中:特别是安全性基于 JDBC 身份验证(Mysql 用作数据库),并且配置是使用基于 java 的注释编写的。

我正在测试输入错误的用户名和密码,因此,正如我在使用的教程中看到的那样,我应该在输入错误的凭据后被重定向到访问被拒绝的页面,而不是我再次被重定向到登录页面。

我不确定这一点,但我认为主要问题在于方法

@Override
protected void configure(HttpSecurity http) throws Exception
{
    http.authorizeRequests()
            //configure security for pages
            .antMatchers("/login").permitAll()
            .antMatchers("/**").access("hasRole('admin')")
            .anyRequest().authenticated()
            //creates login form
            .and().formLogin().loginPage("/login").loginProcessingUrl("/login")
            .defaultSuccessUrl("/home").failureUrl("/accessDenied")
            .usernameParameter("id_utente").passwordParameter("password")
            //catches exceptions http 403 response
            .and().exceptionHandling().accessDeniedPage("/accessDenied");
}

可能没有正确配置,我配置它的方式是:

在查看 Spring 安全文档或互联网后,我没有发现任何类似的问题和该问题的解决方案,也没有发现配置安全层的广泛指南。

下面我提供编写的代码,以便让您看到整个配置,在此先感谢大家。

POM.xml 的内容:

<!-- SPRING SECURITY -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>${spring-security-web}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>${spring-security-config}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>${spring-security-core}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>${spring-security-taglibs}</version>
</dependency>

SecurityConfiguration.java 的内容:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    @Qualifier("securityUserDetailService")
    UserDetailsService userDetailsService;

    /**
     * Manages the encoder to save passwords in the DB
     * not in plain text
     *
     * @return PasswordEncoder object
     */
    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * Manages the configuration of the Authentication manager with
     * user credentials and roles.
     * <p>
     * The AuthenticationManager processes any authentication request.
     *
     * @param auth AuthenticationManagerBuilder object
     * @throws Exception exception
     */
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(authenticationProvider());
    }

    /**
     * Manages the configuration for specific http request.
     *
     * @param http HttpSecurity request
     * @throws Exception exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests()
                //configure security for pages
                .antMatchers("/login").permitAll()
                .antMatchers("/**").access("hasRole('admin')")
                .anyRequest().authenticated()
                //creates login form
                .and().formLogin().loginPage("/login").loginProcessingUrl("/login")
                .defaultSuccessUrl("/home").failureUrl("/accessDenied")
                .usernameParameter("id_utente").passwordParameter("password")
                //catches exceptions http 403 response
                .and().exceptionHandling().accessDeniedPage("/accessDenied");
    }

    /**
     * Manages the storage of user credentials inside database
     *
     * @return The authenticationProvider Object
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider()
    {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        return authenticationProvider;
    }

    @Bean
    public AuthenticationTrustResolver getAuthenticationTrustResolver()
    {
        return new AuthenticationTrustResolverImpl();
    }
}

管理所涉及的 url 的控制器的内容:

@Autowired
AuthenticationTrustResolver authenticationTrustResolver;

/**
 * This method handles Access-Denied redirect.
 */
@GetMapping(value = "/accessDenied")
public String accessDeniedPage(ModelMap model) {
    return "accessDenied";
}

/**
 * Handles login method.
 * If user is not logged, login page is returned,
 * root page otherwise.
 * @return view name
 */
@GetMapping(value = "/login")
public String loginPage() {
    if (isCurrentAuthenticationAnonymous()) {
        return "login";
    } else {
        return "redirect:/";
    }
}

/**
 * If user is already authenticated returns true,
 * false otherwise.
 *
 * @return true is user is authenticated, false otherwise
 */
private boolean isCurrentAuthenticationAnonymous() {
    final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    return authenticationTrustResolver.isAnonymous(authentication);
}

login.jsp 的内容:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
    <head>
        <title>Title</title>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Login</title>
        <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
                integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
                crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
                integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
                crossorigin="anonymous"></script>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
              integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
                integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
                crossorigin="anonymous"></script>
    </head>

    <body>

        <c:url var="loginUrl" value="/login" />

        <div class="leftBar">
            <h2>Login</h2>
        </div>
        <div class="rightBar">
            <div class="col-md-7 col-sm-12">
                <form:form method="post" action="${loginUrl}">
                    <div class="form-group">
                        <label for="userId">ID utente</label>
                        <input type="text" class="form-control" id="userId" placeholder="ID utente">
                    </div>
                    <div class="form-group">
                        <label for="userPwd">Password</label>
                        <input type="password" class="form-control" id="userPwd" placeholder="Password">
                    </div>
                    <button type="submit" name="submit" value="submit" class="btn">Accedi</button>
                </form:form>
            </div>
        </div>
    </body>
</html>

注入 Spring security 进行身份验证的 userService 的内容:

@Service("securityUserDetailService")
public class SecurityUserDetailService implements UserDetailsService
{
    @Autowired
    UtentiService utentiService;

    /**
     * Manages the load of a user along with
     * ID and password.
     *
     * @param s user id
     * @return UserDetail object with ID and password
     * @throws UsernameNotFoundException If user is not found in the system
     */
    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException
    {
        int id = Integer.parseInt(s);

        Utenti user = utentiService.findUserById(id);
        if(user == null)
        {
            throw new UsernameNotFoundException("User with id " + s + " not found");
        }

        return new User(Integer.toString(user.getId_utente()), user.getPassword(), true, true, true, true, getGrantedAuthorities(user));
    }

    /**
     * Determines which roles a particular user has
     *
     * @param user The user for which to find roles
     * @return List containing all roles related to the user
     */
    private List<GrantedAuthority> getGrantedAuthorities(Utenti user)
    {
        List<GrantedAuthority> authorities = new ArrayList<>();

        authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getQualifica()));

        return authorities;
    }
}

SecurityInitializer 类的内容(如一些教程中所示),我将感谢能解释我为什么这个类必须为空的人:

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer
{

}

标签: javaspringspring-mvcspring-security

解决方案


推荐阅读