<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
启动项目后 初始账户user 密码在控制台
Using generated security password: 8a09e79b-5b22-41bf-a211-2226280f6345
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.authorizeRequests()//授权配置
.anyRequest() //所有请求
.authenticated(); //都需要认证
//http.formLogin() // 表单方式
// .and()
// .authorizeRequests() // 授权配置
// .anyRequest() // 所有请求
// .authenticated(); // 都需要认证
}
}
拦截链 | 功能 |
---|---|
UsernamePasswordAuthenticationFilter | 处理基于表单方式的登录认证 |
BasicAuthenticationFilter | 处理HTTPbasic 方式登录 |
FilterSecurityInterceptor | 判断当前身份认证是否成功,是否有相应的权限认证失败抛出异常 |
ExceptionTranslateFilter | 捕获认证失败的异常,返回认证失败重定向的页面、或者权限不足的相应信息 |
主要内容 org.springframework.security.core
自定义
UserDetails
,或者用 自带的接口实现类
// 源码
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
//保存用户信息的 对象
public interface UserDetails extends Serializable {
//获取用户包含的权限,
Collection<? extends GrantedAuthority> getAuthorities();
// 用户密码账户, 一开始会是名为的方式
String getPassword();
String getUsername();
// 账户是否过期
boolean isAccountNonExpired();
//账户是否锁定
boolean isAccountNonLocked();
// 账户密码是否过期
boolean isCredentialsNonExpired();
//账户是否可用
boolean isEnabled();
}
实现
UserDetailsService
//自定义用户 详情
@Configuration
public class UserDetailService implements UserDetailsService {
//在 security 配置类中 注入BCryptPasswordEncoder
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// MyUser 模拟数据库
MyUser user = new MyUser();
user.setUserName(username);
user.setPassword(passwordEncoder.encode("123456"));
// 输出加密密码
System.out.println(user.getPassword());
//返回 security 建权好的对象
return new User(username, user.getPassword(), user.isEnabled(),
user.isAccountNonExpired(), user.isCredentialsNonExpired(),
user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
// 默认配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//手动注入 密码加密到 ioc 容器中
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder() ;
}
}
**注意:**当 loginPage 指定了跳转登陆页面的URL 后,.antMatchers(“/login.html”).permitAll() 来设置不被拦截。不然会死循环
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.loginPage("/login.html")
.loginProcessingUrl("/login")//处理表单登陆的url
.and()
.authorizeRequests() // 授权配置
.antMatchers("/login.html").permitAll()
.anyRequest() // 所有请求
.authenticated(); // 都需要认证
.and().csrf().disable();
}
@Configuration
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {
//手动注入 密码加密到 ioc 容器中
@Bean
public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder() ; }
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/skip") //处理跳转的url
.loginProcessingUrl("/login") //处理登陆的url
.and()
.authorizeRequests()//授权配置
.antMatchers("/login.html","/skip").permitAll() //匹配路径,不做权限认证
.anyRequest() //所有请求
.authenticated() //都需要认证
.and().csrf().disable();
}
}
@RestController
public class BrowserSecurityController {
// security 提供的 缓存请求的对象
private RequestCache requesrtCache = new HttpSessionRequestCache();
// security 提供的 重定向的方法
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@GetMapping("sikp")
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String sikpAuthenticaiton(HttpServletRequest req, HttpServletResponse resp)throws IOException {
//获取本次请求额 http 信息
SavedRequest savedRequest = requesrtCache.getRequest(req, resp);
if (savedRequest != null) {
String targetUrl = savedRequest.getRedirectUrl();
// 请求是 .html 结尾 就是重定向 到登陆页面
if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
redirectStrategy.sendRedirect(req,resp,"/login.html");
}
}
return "访问的资源需要身份认证";
}
}
localhost:8080/hello 重定向到 http://localhost:8080/skip
http://localhost:8080/login.html 重定向到表单登陆
**注意: security 的拦截器是实现接口方法后会自动调用 WebSecurityConfigurerAdapter
在练习的时候,多个配置文件记得注释掉 其他的接口,我一开始只注释了@Config 导致多个拦截器冲突,后写的一直不生效!!!**
AuthenticationSuccessHandler
主要实现接口
在到配置类中配置
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private ObjectMapper mapper; //jackson 工具
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
//编写成功登陆 的业务逻辑
//这里面 给前端返回一个 json 数据
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(mapper.writeValueAsString(authentication));
System.out.println("登陆成功");
}
}
@Autowired
public MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/skip") //处理跳转的url
.loginProcessingUrl("/login") //处理登陆的url
.successHandler(myAuthenticationSuccessHandler)
......
常见业务如请求重定向
// 请求信息 , 转发工具 private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); SavedRequest savedRequest = requestCache.getRequest(request, response); redirectStrategy.sendRedirect(request, response, "目标页面");
步骤同上 实现
AuthenticationSuccessHandler
只是在配置文件配置.failureHandler()
失败异常对应接口AuthenticationException