login-page // 自定义登录页面的url,例如login.html
login-processing-url // 登录请求拦截的url,即form表单提交的url,默认值是/login
// 以下2个需要配合使用,如果需要认证成功跳转的url,则always-use-default-target需要设置为true
// 如果使用authentication-success-handler-ref处理认证成功,则以下两个属性失效
default-target-url // 默认登录成功后跳转的url
always-use-default-target // 是否总是使用默认登录成功后的url,即default-target-url,默认为false
authentication-failure-url // 登录失败跳转的url
username-parameter // 用户名的请求字段,即form表单里用户名的name属性,默认值为username
password-parameter // 密码的请求字段,即form表单里密码的name属性,默认值为password
// 以下1个不能和default-target-ur、always-use-default-target同时使用,会覆盖这两个
authentication-success-handler-ref // 指向一个AuthenticationSuccessHandlerImpl处理认证成功的bean
// 以下是不太常用的(就我个人而言),所以不是很了解
authentication-failure-handler-ref // 指向一个AuthenticationFailureHandlerImpl处理认证失败的bean
authentication-details-source-ref // 指向一个AuthenticationDetailsSourceImpl,在认证过滤器中和私用
authentication-success-forward-url // 用于authentication-success-handler-ref
authentication-failure-forward-url // 用于authentication-failure-handler-ref
本文讲解是通过我正在写的项目(Dubbo+Zookeeper)来讲解的,都有详细解释。
contextConfigLocation
classpath:spring/spring-security.xml
org.springframework.web.context.ContextLoaderListener
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
1.修改Spring-Security.xml文件,配置一个自定义认证信息bean
2.创建UserDetailServiceImpl实现UserDetailService接口
public class UserDetailServiceImpl implements UserDetailsService {
// 通过bean的方式注入进来
private SellerService sellerService;
public void setSellerService(SellerService sellerService) {
this.sellerService = sellerService;
}
/**
* 登录时自动调用
* @param username 用户名
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 定义权限的集合 - 全部存的是权限
List authorityList = new ArrayList<>();
// 添加用户拥有的角色 - 可以从数据库中读取
authorityList.add(new SimpleGrantedAuthority("ROLE_SELLER"));
// 判断用户名是否为空,如果为空直接返回null
if(username == null){
return null;
}
// 在数据库中去查对象
Seller seller = sellerService.findById(username);
// 参数:用户名、密码、权限集合 密码前拼接{noop} 表示不加密
User user = new User(username,seller.getPassword(),authorityList);
return user;
}
}
3.在认证权限管理器中指定加密工具类(注入加密工具类、指定加密工具类)
上诉代码解释:
这里因为在springMVC.xml中配置了包扫描地址为Controller包,而UserDetailService不在Controller包下,所以没办法通过@Reference注入sellerService(因为是Dubbo项目,这里读者如果不是Dubbo项目,即可以通过@Autowired注入时,就不用通过这种方式来注入,请直接忽略下面的解释)。
注:如果是Dubbo项目,还得通过dubbo:reference把sellerService接口服务bean注入进来,如下:
在对应的Controller类注入PasswordEncoder,通过它的encode方法对明文密码进行加密。
@Autowired
private PasswordEncoder passwordEncoder;
@RequestMapping("/add")
public Result add(@RequestBody Seller seller){
// 获取明文密码
String password = seller.getPassword();
// 对明文密码进行加密
String securityPassword = passwordEncoder.encode(password);
// 把加密后的密码存储到seller中
seller.setPassword(securityPassword);
Result result = sellerService.add(seller);
return result;
}
1.创建拦截器
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
}
}
2.重定向的方式(sendRedirect)
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
System.out.println("登陆成功");
// 手动跳转
httpServletResponse.sendRedirect("/admin/index.html");
}
}
3.请求转发的方式(forward),与重定向一样,在方法里写请求转发的代码即可
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
System.out.println("登陆成功");
// 手动跳转
httpServletRequest.getRequestDispatcher("/admin/index.html")
.forward(httpServletRequest,httpServletResponse);
}
}
注:如果你请求转发的页面含有iframe嵌套页面,则还需要在嵌套页面写入详细的url,如下图
1.修改Spring-Security.xml配置文件
2.创建拦截器AuthenticationFailureHandlerImpl,实现AuthenticationFailureHandler接口
3.根据异常信息,判断认证异常还是用户名异常。然后写到session中,前端发送请求从session中取出信息
1.修改Spring-Security.xml配置文件,在失败url后加一个参数
2.前端通过JS获取参数进行判断和回显,如果地址栏有error参数,那么就是失败了
// 获取地址栏中的name参数
function getUrlParam(name) {
return decodeURIComponent(
(new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ""])[1].replace(/\+/g, '%20')) || null
}
// 检查有没有获取到
function checkError() {
let res = getUrlParam("error");
if (res != null) { // 获取到了error
// 可以找个标签给他安排上
console.log("登录失败,原因可能是:未通过审核、审核中、账户已被关闭、账号或密码错误!");
// 修改地址栏
window.history.pushState(null, null, "http://localhost:8083/shoplogin.html");
// 回显信息
$("#error").text("登录失败,原因可能是:未通过审核、审核中、账户已被关闭、账号或密码错误!");
}
}
4.每次进入这个页面就调用一次checkError方法即可