java - 使用 Java 注释配置的 Spring Security 配置错误
问题描述
早上好。
我有一个基于 Spring MVC 并由 Spring Security 保护的应用程序,特别是我正在使用这些版本:
- Spring Security:5.3.1.RELEASE;
- Spring MVC:5.2.5.RELEASE。
主要问题
在使用基于 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");
}
可能没有正确配置,我配置它的方式是:
- 自定义表单登录(process by
.and().formLogin().loginPage("/login").loginProcessingUrl("/login")
)甚至在首页也显示; - 如果用户正确输入凭据,他将被重定向到主页 (
.defaultSuccessUrl("/home")
); - 否则他会被重定向到 accessDenied 页面 (
.failureUrl("/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
{
}
解决方案
推荐阅读
- dynamic - Ecto:在每次迁移之前或之后运行 sql 脚本
- python - Python SQLITE3 Insert into and On conflict do update with variables - 语法问题?
- node.js - package.json 如何用多个 package.json 构建项目?
- c++ - 这个 C++ 函数在运行时会做什么?
- geolocation - ionic 5 @ionic-native/geolocation 添加提供者问题
- html - 在不改变父元素宽度的情况下替换一行上的两个 div
- java - 属性中的 Cedilla 不被读取
- google-chrome - Chrome 和 Firefox 之间的奇怪行为
- mysql - VB.NET MySQL:错误'无法将'System.Int32'类型的对象转换为'MySql.Data.MySqlClient.MySqlDataReader
- tensorflow - 运行 RNN-LSTM 时得到奇怪的准确度数字