需求
Spring Security默认的登录表单只有username和password,但实际业务中我们可能需要使用其他的字段校验,因此需要重写认证部分。
web.xml
<!-- 配置SpringSecurity过滤器 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
security.xml
spring security的配置,需要web.xml扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 以下页面不被拦截 -->
<http pattern="/login/**" security="none"></http>
<http pattern="/static/**" security="none"></http>
<!-- 页面拦截规则 -->
<http use-expressions="false">
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/login/login.jsp"
authentication-failure-url="/login/login.jsp?error=true"
login-processing-url="/login.do"
default-target-url="/index.jsp"
authentication-details-source-ref="authenticationDetailsSource"
/>
<logout logout-url="/logout.do" logout-success-url="/login/login.jsp"/>
<csrf disabled="true"/>
<headers>
<frame-options policy="SAMEORIGIN"/>
</headers>
</http>
<!-- 认证管理器 -->
<authentication-manager>
<!---使用自定义的认证管理器->
<authentication-provider ref="authenticationProvider" ></authentication-provider>
</authentication-manager>
<!---自定义认证管理器->
<beans:bean id="authenticationProvider" class="com.controller.login.LoginAuthenticationProvider"></beans:bean>
<beans:bean id="authenticationDetailsSource" class="com.controller.login.LoginAuthenticationDetailsSource"></beans:bean>
</beans:beans>
自定义类
LoginAuthenticationDetailsSource
public class LoginAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
//DetailSource返回自定义的认证对象
return new LoginWebAuthenticationDetails(context);
}
}
LoginWebAuthenticationDetails
这个类用于收集表单提交的参数
public class LoginWebAuthenticationDetails extends WebAuthenticationDetails{
private static final long serialVersionUID = 336993541165304236L;
private String serverRandomId;
private String encryptedClientRandom;
private String encryptedInputValue;
private String username;
private String password;
public LoginWebAuthenticationDetails(HttpServletRequest request) {
super(request);
serverRandomId = request.getParameter("serverRandomId");
encryptedClientRandom = request.getParameter("encryptedClientRandom");
encryptedInputValue = request.getParameter("encryptedInputValue");
username = request.getParameter("username");
password = request.getParameter("password");
}
public String getServerRandomId() {
return serverRandomId;
}
public String getEncryptedClientRandom() {
return encryptedClientRandom;
}
public String getEncryptedInputValue() {
return encryptedInputValue;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
LoginAuthenticationProvider
这个类用于登录认证逻辑的判断
public class LoginAuthenticationProvider implements AuthenticationProvider{
@Autowired
private GlobalPermissionService globalPermissionService;
@Autowired
private ISysAccountService sysAccountService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 这里通过我们自定义的对象,取出收集的表单参数进行逻辑验证
LoginWebAuthenticationDetails details = (LoginWebAuthenticationDetails) authentication.getDetails();
String encryptedClientRandom = details.getEncryptedClientRandom();
String username = details.getUsername();
// 这里是验证逻辑
if (验证失败) {
throw new DisabledException("用户名或者密码不正确!");
}
// 授权
List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
List<GrantedAuthority> list = globalPermissionService.getUserGrantedAuthority(username);
grantedAuths.addAll(list);
// 验证成功 返回这个对象
return new UsernamePasswordAuthenticationToken(username, "", grantedAuths);
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
登录页面
<form action="${pageContext.request.contextPath}/login.do" id="loginForm" method="post">
<table class="table" id="LoginBox">
<tr>
<td id="logo"></td>
</tr>
<tr style="height:80px;">
<td style="vertical-align: bottom;text-align:left;"><span class="loginText">用户名</span></td>
</tr>
<tr>
<td><input type="text" class="form-control inputSize" name="username" id="username"></td>
</tr>
<tr style="height:40px;">
<td style="text-align:left;"><span class="loginText">密码</span></td>
</tr>
<tr>
<td>
<input type="password" class="form-control inputSize" name="password" id="password" onKeyDown="keydownEvent()">
</td>
</tr>
<tr>
<td>
<span style="color:red;margin-left: 25px;">${SPRING_SECURITY_LAST_EXCEPTION.message}</span>
</td>
</tr>
<tr>
<td>
<input type="button" class="btn btn-self-blue" value="登录" id="LoginBtn"/>
</td>
</tr>
</table>
</form>
登录页面注意:
如果验证失败,我们还跳转到登陆页面,同时Spring Security会在session中存储错误信息,错误信息的获取使用 ${SPRING_SECURITY_LAST_EXCEPTION.message}