SpringSecurity
一、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
二、后端代码
(1)、配置类编写
1、配置PasswordEncoder密码编码器
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder getPwdEncoder(){
return new BCryptPasswordEncoder();
}
}
2、修改配置类
- successForwardUrl()登录成功后跳转地址
- loginPage() 登录页面
- loginProcessingUrl登录页面表单提交地址,此地址可以不真实存 在。
- antMatchers():匹配内容
- permitAll():允许
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 表单认证
http.formLogin()
.loginProcessingUrl("/login") //当发现/login 时认为是登录,需要执行UserDetailsServiceImpl
.successForwardUrl("/toMain") //此处是 post 请求
.failureForwardUrl("/fail")//登录失败跳转地址
.loginPage("/toLogin")
.usernameParameter("myusername") //自定义前端参数名称
.passwordParameter("mypassword");
// url 拦截 http.authorizeRequests() .antMatchers("/login.html") .permitAll()
//login.html 不需要被认证 .anyRequest().authenticated();
//所有的请求都必须被认证。必须登录后才能访问。
//关闭 csrf 防护
http.csrf().disable();
// url 拦截
http.authorizeRequests()
.antMatchers("/login.html")
.permitAll() //login.html 不需要被认证
.antMatchers("/fail.html")
.permitAll() //fail.html 不需要被认 证
.anyRequest().authenticated();//所有的请求都必须被认证。必 须登录后才能访问。
}
@Bean
public PasswordEncoder getPe(){
return new BCryptPasswordEncoder();
}
}
(2)、编写认证服务实现类
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
//1. 查询数据库判断用户名是否存在,如果不存在抛出相应异常
if(!username.equals("admin")){ throw new UsernameNotFoundException("用户名不存在");
}
//把查询出来的密码进行解析,或直接把 password 放到构造方法中。
//理解:password 就是数据库中查询出来的密码,查询出来的内容不是 123
String password = encoder.encode("123");
return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
(3)、自定义登陆成功、失败处理器
1、编写一个控制器类实现AuthenticationSuccessHandler 接口
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException
{
//Principal 主体,存放了登录用户的信息
User user = (User)authentication.getPrincipal();
System.out.println(user.getUsername());
System.out.println(user.getPassword());//密码输出为 null
System.out.println(user.getAuthorities()); //重定向到百度。这只是一个示例,具体需要看项目业务需求
httpServletResponse.sendRedirect("http://www.baidu.com");
}
}
2、编写一个控制器类实现AuthenticationFailureHandler 接口
public class MyForwardAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect("/fail.html");
}
}
3、配置设置
http.formLogin()
.loginProcessingUrl("/login") //当发现/login 时认为是登录,需 要执行UserDetailsServiceImpl
.successHandler(new MyAuthenticationSuccessHandler())
//.successForwardUrl("/toMain") //此处是 post 请求
.failureHandler(new MyForwardAuthenticationFailureHandler())
// .failureForwardUrl("/fail") //登录失败跳转地址
.loginPage("/login.html");
三、权限和角色控制
1、匹配规则
(1)、anyRequest()
.anyRequest().authenticated();
(2)、antMatcher()
public C antMatchers(String... antPatterns)
参数是不定向参数,每个参数是一个 ant 表达式,用于匹配 URL 规则规则如下:
? 匹配一个字符
*匹配 0 个或多个字符
** 匹配 0 个或多个目录
.antMatchers("/js/**").permitAll()
.antMatchers("/**/*.js").permitAll()
(3)、regexMatchers()
使 用 正 则 表 达 式 进 行 匹 配 。 和 antMatchers() 主 要 的 区 别 就 是 参 数 ,
antMatchers()参数是 ant 表达式,regexMatchers()参数是正则表达式。
.regexMatchers(".+[.]js").permitAll()
(4)、mvcMatchers()
mvcMatchers()适用于配置了 servletPath 的情况。servletPath 就是所有的
URL 的 统 一 前 缀 。 在 SpringBoot 整 合 SpringMVC 的 项 目 中 可 以 在
application.properties 中添加下面内容设置 ServletPath。
spring.mvc.servlet.path= /etc
在 Spring Security 的配置类中配置.servletPath()是 mvcMatchers()返回值特有的方法,antMatchers()和 regexMatchers()没有这个方法。在 servletPath()
中 配 置 了 servletPath 后 , mvcMatchers() 直 接 写 SpringMVC 中@RequestMapping()中设置的路径即可。
.mvcMatchers("demo").servletPath("/etc").permitAll()
如果不习惯使用 mvcMatchers()也可以使用 antMatchers(),下面代码和上面代码是等效的
.antMatchers("/etc/demo").permitAll()
2、url权限控制
permitAll()
permitAll()表示所匹配的URL任何人都允许访问。
authenticated()
authenticated()表示所匹配的URL需要被认证才能访问。
anonymous()
anonymous()表示可以匿名访问匹配的URL。和permitAll()效果类似,对于匿名访问的用户,Spring Security支持为其建立一个匿名AnonymousAuthenticationToken存放在SecurityContextHolder中,这就是所谓的匿名认证。这样在以后进行权限认证或者做其它操作时我们就不需要再判断SecurityContextHolder中持有的Authentication对象是否为null了,而直接把它当做一个正常的Authentication进行使用就OK了。
denyAll()
denyAll()表示所匹配的URL 都不允许被访问。
rememberMe()
被“remember me”的用户允许访问。
fullyAuthenticated()
用户通过正常登录认证的而不是被remember me 的,才可以访问。
3、根据权限控制
hasAuthority(String)
判断用户是否具有特定的权限,用户的权限是在自定义登录逻辑中创建 User 对象时指定的。下图中 admin 就是用户的权限。admin 严格区分大小写。
.antMatchers("/main1.html").hasAuthority("admin")
hasAnyAuthority(String …)
如果用户具备给定权限中某一个,就允许访问。下面代码中由于大小写和用户的权限不相同,所以用户无权访问/main1.htm
.antMatchers("/main1.html").hasAnyAuthority("adMin","admiN")
4、根据角色控制
hasRole(String)
如果用户具备给定角色就允许访问。否则出现 403。
参数取值来源于自定义登录逻辑 UserDetailsService 实现类中创建 User 对象时给 User 赋予的授权。
在给用户赋予角色时角色需要以:ROLE_ 开头,后面添加角色名称。例如:
ROLE_abc 其中 abc 是角色名,ROLE_是固定的字符开头。使用 hasRole()时参数也只写 abc 即可。否则启动报错。
.antMatchers("/main1.html").hasRole("abc")
hasAnyRole(String …)
如果用户具备给定角色的任意一个,就允许被访问
四、自定义异常处理
实现AccessDeniedHandler 接口
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException
{
//设置响应状态码 403
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpServletResponse.setHeader("Content-Type","application/json;charse t=utf-8") ;
PrintWriter out = httpServletResponse.getWriter();
out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理 员!\"}");
out.flush();
out.close();
}
修改配置
http.exceptionHandling()
.accessDeniedHandler(myAccessDeniedHandler);