目录
一、SpringSecurity介绍
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
二、springboot整合Spring Security
1、新建
使用spring initializr 新建springboot项目
记得勾选Spring Security
2、
控制层:
/**
* @author Mae
*/
@Controller
public class UserController {
@RequestMapping
public String indexPage() {
return "redirect:index.html";
}
}
没有指定默认登录页,则使用security默认登陆页面
默认登陆页
用户名默认为 user
密码为 控制台打印的密文
登录后就会跳转到首页
三、自定义登录逻辑和权限
1、持久层
即数据库根据用户名查询用户
/**
* @author Mae
*/
@Mapper
public interface UserMapper {
/***
* 查找用户名
* @param username
* @return
*/
User findUsername(String username);
}
对应的xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atmae.springsecurity.mapper.UserMapper">
<select id="findUsername" resultType="com.atmae.springsecurity.pojo.User">
select *
from t_user
where username = #{username}
</select>
</mapper>
2、
配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder getPw() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
/** 表单提交*/
http.formLogin()
.usernameParameter("username")
.passwordParameter("password")
/** 当发现/login时 认为是登录 需和表单提交地址相同*/
.loginProcessingUrl("/login")
/** 自定义登录页面*/
.loginPage("/login.html")
/** 成功后执行post请求*/
.successForwardUrl("/index")
/** 失败后执行post请求*/
.failureForwardUrl("/error");
http.authorizeHttpRequests()
/** 配置路径放行*/
.antMatchers("/error.html").permitAll()
.antMatchers("/login.html").permitAll()
.antMatchers("/**/*.png").permitAll()
/** 正则表达式 放行*/
.regexMatchers(".+[.]png").permitAll()
/** 权限管理 是改权限才能后登录member页面*/
.antMatchers("/member.html").hasAnyAuthority("admin")
/** 角色判断 是改角色才能够登录member页面*/
.antMatchers("/member.html").hasRole("student")
/** 所有请求都必须被认证*/
.anyRequest().authenticated();
/** 关闭防火墙*/
http.csrf().disable();
}
}
BCryptPasswordEncoder:密码加密算法,其过程不可逆
相应的登录页面:
<form action="/login" method="post">
<label for="username"></label><input type="text" id="username" name="username" placeholder="请输入用户名">
<label for="password"></label><input type="password" id="password" name="password" placeholder="请输入密码">
<input type="submit" value="提交">
</form>
注:
- 1、action中的url地址必须与
.loginProcessingUrl("/login")
中url地址相同只有遇到/login时才会被认为是登录 - 2、
.usernameParameter("username")和.passwordParameter("password")
中的参数如何跟表单中name属性相同则可省略,否则不可省略
业务层:
/**
* @author Mae
*/
@Service
public class UserServiceImpl implements UserDetailsService {
@Resource
private UserMapper userMapper;
@Resource
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/** 查询数据库判断用户名是否存在*/
User user = userMapper.findUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名没有找到");
}
/** 把查询出的密码(注册时已经过加密)进行解析,或者直接把密码放入构造方法*/
String password = passwordEncoder.encode(user.getPassword());
return new org.springframework.security.core.userdetails.User(username, password, AuthorityUtils
.commaSeparatedStringToAuthorityList("admin,normal,ROLE_student"));
}
}
/** 表示设置权限和角色 admin和normal为权限 ROLE_student为角色
* 注意:ROLE_不可省略
*/
AuthorityUtils
.commaSeparatedStringToAuthorityList("admin,normal,ROLE_student")
数据库:
会员页可以正常跳转
将业务层方法改为
return new org.springframework.security.core.userdetails.User(username, password, AuthorityUtils
.commaSeparatedStringToAuthorityList("admin,normal0,ROLE_student0"));
配置类不变
首页可以正常跳转
会员页无法正常跳转 报状态码403即权限不足
四、自定义成功和失败处理器
原因:目前项目都是前后端分离,为了解决跨域问题
.successForwardUrl("/index")和.failureForwardUrl("/error");
只能处理post请求
定义成功处理器
/**
* @author Mae
*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private String url;
public MyAuthenticationSuccessHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.sendRedirect(url);
}
}
配置类http .successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com")
失败处理器配置相同
即实现AuthenticationFailureHandler
接口
五、自定义403状态码错误页面
查看403状态码
一定不要忘记添加Component注解 交给spring管理
/**
* @author Mae
*/
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
/** 403状态码*/
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
/** 使用json传输数据*/
response.setHeader("Content-Type","application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write("{\"status\":\"error\",\"meg\":\"权限不足,请联系管理员\"}");
writer.flush();
writer.close();
}
}
在配置类中注入并且配置异常处理
@Autowired
private MyAccessDeniedHandler myAccessDeniedHandler;
/** 异常处理*/
http.exceptionHandling()
.accessDeniedHandler(myAccessDeniedHandler);
六、注解配置
首先在springboot启动类中开启注解(默认关闭)
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SecuritydemoApplication {
public static void main(String[] args) {
SpringApplication.run(SecuritydemoApplication.class, args);
}
}
在控制层中
@PreAuthorize:在登录之前调用此方法 可以省略ROLE_
@Secured:相同作用 但是角色前必须加ROLE_
@Secured("ROLE_student0")
@PreAuthorize("hasRole('ROLE_student0')") /** 可以不以Role开头*/
@RequestMapping("/index")
public String indexPage() {
return "redirect:index.html";
}
成功跳转