FormLogin
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1 官方默认操作
登录地址:
密码:
2 自定义账号密码
通过源码可以知道,我们可以去实现该接口,返回自定义的包含密码和权限的User对象。springsecurity会在其他地方拿出该User对象的password去跟前端传来的password做比对,比对成功则通过验证
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//我们自定义的用户名是“xxjqr”
if (!Objects.equals("xxjqr", username)) {
//抛出springsecurity自带的N多异常对象
throw new UsernameNotFoundException("用户名不匹配");
}
//String password = new BCryptPasswordEncoder().encode("1234");
//这里我们先不从数据库中取密码,我们使用自定义的
String password = passwordEncoder.encode("1234");
//真实开发中应该从数据库中提取用户权限和角色,这里我们直接构造normal权限和admin的角色。角色默认的前缀都是ROLE_
return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("low,ROLE_admin"));
}
@Bean
public PasswordEncoder passwordEncoder() {
//使用BCrypt加密机制
return new BCryptPasswordEncoder();
}
}
到这里我们已经可以自定义登录的账号密码了,但是登录成功并没有显示其他东西,因为官方貌似就给了一个登录页面而已
3 认证授权逻辑自定义配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);
//自定义form表单的登录页面,和登录的接口;
http.formLogin().loginPage("/login.html")
//这个接口是不需要我们写的,是spring去代理的,但是我们可以自定义登陆逻辑,这个路径必须和form表单组件的action路径一致
.loginProcessingUrl("/login")
// 登录成功后跳转路径,为啥不直接写home.html呢,因为security帮我们跳转是使用的post请求,所以我们要用接口去手动跳转
//.successForwardUrl("/home")
.defaultSuccessUrl("/home.html")
// 这个方式不生效,有待研究
//.failureForwardUrl("/error");
.failureUrl("/error.html");
/*这里做个小总结,ForwardUrl都是使用post方式去请求地址
所以successForwardUrl,failureForwardUrl,都需要后端
去提供接口再做页面跳转,并且failureForwardUrl还不生效*/
//授权
http.authorizeRequests()
//登录页面和错误页面要开放,成功页面是登录成功后的,所以有权限。开放多个用逗号隔开“a”,"b"
.antMatchers("/login.html","/error.html").permitAll()
//但是其他所有请求必须登录
.anyRequest().authenticated();
//关闭csrf防火墙
http.csrf().disable();
}
}
到目前为止里面大概内容就是:
1 自定义登录页面
2 自定义登录时对账号密码的校验
3 定义哪些url拦截,哪些不拦截
4 定义登陆成功和失败后的页面跳转
4 权限控制细化
4.1 功能清单
1 自定义handler处理登陆成功、失败、无权限跳转
2 针对不同的请求方式的方法做拦截
3 正则表达式的方式过滤
4 ip过滤
5 直接通过access方法做过滤控制
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private MyAccessDeniedHandler accessDeniedHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);
http.formLogin().loginPage("/login.html")
.loginProcessingUrl("/login")
//只用自定义的handler来处理登录成功,失败的逻辑
.successHandler(new MySuccessHandler("/home.html"))
.failureHandler(new MyFailureHandler("/error.html"));
//授权
http.authorizeRequests()
.antMatchers("/login.html", "/error.html").permitAll()
//对权限做过滤控制
.antMatchers("/girl.html").hasAnyAuthority("normal")
//对角色做过滤控制
.antMatchers("/girl.html").hasAnyRole("admin")
.anyRequest().authenticated();
// 不同方式的请求方法做拦截
// antMatchers()和.regexMatchers()
//.antMatchers(HttpMethod.DELETE,"/index.html")
// 针对ip做过滤
//.antMatchers("").hasIpAddress(“”)
// 通过access方法来处理,因为其他权限控制方法底层都是调用的access
//.antMatchers("").access("hasAnyRole('admin')")
//当登录成功后,访问到没有授权的资源时
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
//关闭csrf防火墙
http.csrf().disable();
}
}
MySuccessHandler
public class MySuccessHandler implements AuthenticationSuccessHandler {
private String url;
public MySuccessHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
User user = (User)authentication.getPrincipal();
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getAuthorities());
httpServletResponse.sendRedirect(url);
}
}
MyAccessDeniedHandler
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
//重定向跳转
httpServletResponse.sendRedirect("/403.html");
}
}
MyFailureHandler
public class MyFailureHandler implements AuthenticationFailureHandler {
private String url;
public MyFailureHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
System.out.println("密码错误了");
httpServletResponse.sendRedirect(url);
}
}
4.2 界面展示
登陆成功后跳到 home.html
从上面的代码中我们知道 girl.html 资源需要 normal权限 或者 admin 角色
登陆的用户 xxjqr 具有 low 权限 和 admin角色
所以点击 看美女 可以访问
当我们在代码中把 xxjqr 的 admin角色删除后,再点击 看美女
5 自定义权限校验
定义自定义权限的类和方法
@Service
public class MyServiceImpl {
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
//获取主体
Object obj = authentication.getPrincipal();
//判断主体是否是UserDetails类型
if (obj instanceof UserDetails) {
//获取权限
UserDetails userDetails = (UserDetails) obj;
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
//判断请求的uri是否在权限里
return authorities.contains(new SimpleGrantedAuthority(request.getRequestURI()));
}
return false;
}
}
然后自定义配置就变成了
此时,当我们想访问"/home.html"时,那用户必须要有改权限
Post、Json方式登录