- 1. 基本认证
- 1.1 第一个Spring Security项目快速搭建
- 1.2 流程分析
- 1.3 默认用户生成
- 1.4 默认页面生成
- 2. 登录表单配置
- 2.1 快速入门
- 2.2 配置细节
- 3.登录用户数据的获取
- 3.1 从SecurityContextHolder中获取
- 3.2 从当前请求对象中获取
- 4. 用户定义
- 4.1 基于内存
- 4.2 基于JdbcUserDetailsManager
- 4.3 基于MyBatis
打开idea,选择创建新项目,选择Spring Initializr,之后按步骤输入相关信息即可
如果因为网络原因无法创建,可以采用以下方式,进入网站https://start.spring.io/:
填写相关信息后,点击GENERATE,会下载一个压缩包,解压该压缩包,修改文件夹名称,使用idea打开项目,点击pom.xml,然后选择open as project即可
完成以上步骤之后,打开项目中的piom文件,加入以下两个依赖:
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security
创建一个controller包,在改包下面建立一个HelloController.java文件,内容如下:
package cn.edu.xd.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello";
}
@GetMapping("/world")
public String world(){
return "world";
}
}
打开浏览器输入:http://localhost:8080, 会显示如下页面:
输入默认的用户名:user, 密码显示在idea的控制台:
输入相应的用户名和密码后, 在浏览器输入:http://localhost:8080/hello/
页面会显示hello字符串
- 客户端发送hello请求
- hello请求被过滤器链拦截,发现用户未登录,抛出访问拒绝异常
- 发生的访问异常在ExceptionTranslationFilter被捕获,调用LoginUrlAuthenticationEntryPoing要求客户端重定向到login请求
- 客户端发送login请求
- login请求被DefaultLoginPageGeneratingFiletr拦截,生成并返回登录页面
所以一开始输入hello请求会先跳转到login页面
1.3 默认用户生成package org.springframework.security.core.userdetails;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
public interface UserDetails extends Serializable {
Collection extends GrantedAuthority> getAuthorities();//返回当前账户拥有的权限
String getPassword();//返回当前账户的密码
String getUsername();//返回当前账户的用户名
boolean isAccountNonExpired();//返回当前账户是否过期
boolean isAccountNonLocked();//返回当前账户是否被锁定
boolean isCredentialsNonExpired();//返回当前账户用户凭证是否过期
boolean isEnabled();//返回当前账户是否可用
}
UserDetails是Spring Security框架中的一个接口,该接口定义了上面7个方法
UserDetails类:用户定义
UserDetailsService类:提供用户数据源
package org.springframework.security.core.userdetails;
public interface UserDetailsService {
//查询用户的方法 var1:用户名
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
实际项目中,开发者可以自己实现 UserDetailsService接口,当然框架中页对该接口有几个默认的实现类
package org.springframework.boot.autoconfigure.security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.DispatcherType;
import org.springframework.util.StringUtils;
@ConfigurationProperties(
prefix = "spring.security"
)
public class SecurityProperties {
public static final int BASIC_AUTH_ORDER = 2147483642;
public static final int IGNORED_ORDER = -2147483648;
public static final int DEFAULT_FILTER_ORDER = -100;
private final SecurityProperties.Filter filter = new SecurityProperties.Filter();
private final SecurityProperties.User user = new SecurityProperties.User();
public SecurityProperties() {
}
public SecurityProperties.User getUser() {
return this.user;
}
public SecurityProperties.Filter getFilter() {
return this.filter;
}
public static class User {
private String name = "user";
private String password = UUID.randomUUID().toString();
private List roles = new ArrayList();
private boolean passwordGenerated = true;
public User() {
}
......
}
上述类中提供了默认的用户名user和密码(UUID)
如果想要修改默认名和密码,可以在application.properties在添加以下配置:
spring.security.user.name=tom spring.security.user.password=123
打开浏览器,输入自定义的用户名和密码即可登录
1.4 默认页面生成默认登录页面:localhost:8080/login
默认退出页面:http://localhost:8080/logout
question: 这两个默认页面从哪来?
ans: 这两个页面由下面两个类生成
package org.springframework.security.web.authentication.ui;
//省略import
public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
//列出两个主要方法
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean loginError = this.isErrorPage(request);
boolean logoutSuccess = this.isLogoutSuccess(request);
if (!this.isLoginUrlRequest(request) && !loginError && !logoutSuccess) {
chain.doFilter(request, response);
} else {
String loginPageHtml = this.generateLoginPageHtml(request, loginError, logoutSuccess);
response.setContentType("text/html;charset=UTF-8");
response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
response.getWriter().write(loginPageHtml);
}
}
}
private String generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess) {
String errorMsg = "Invalid credentials";
if (loginError) {
HttpSession session = request.getSession(false);
if (session != null) {
AuthenticationException ex = (AuthenticationException)session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
errorMsg = ex != null ? ex.getMessage() : "Invalid credentials";
}
}
String contextPath = request.getContextPath();
StringBuilder sb = new StringBuilder();
sb.append("n");
..........省略代码
sb.append(" n");
}
Iterator var7;
Entry relyingPartyUrlToName;
String url;
String partyName;
if (this.oauth2LoginEnabled) {
..........省略代码
}
sb.append("n");
}
if (this.saml2LoginEnabled) {
sb.append("Login with SAML 2.0");
..........省略代码
sb.append("n");
}
sb.append("n");
}
sb.append("n");
sb.append("


