SpringBoot集成Spring Security(一)登录注销
同个人网站 https://www.serendipper-x.cn/,欢迎访问 !
SpringBoot集成Spring Security(二)注册 、密码加密、修改密码
写在前面
Spring Security是一种基于 Spring AOP 和 Servlet 过滤器的安全框架。它提供全面的安全性解决方案,同时在 Web 请求级和方法调用级处理身份确认和授权。
由于最近写的项目用到了这方面知识,这里做一些总结。下面直接看代码
一、创建项目
这里以多模块项目
为例。
多模块项目优点:
帮助项目划分模块,鼓励重用,防止POM变得过于庞大,方便各个模块的构建,而不用每次都构建整个项目,使得针对某个模块的特殊控制更为方便。
二、引入pom依赖
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
三、web层
项目最核心的代码
SecurityConfig.java
/**
* @author xiao
* 使用springsecurity对用户登录、注销以及权限进行控制
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private StudentService studentService;
@Autowired
private ObjectMapper objectMapper;
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(studentService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// .authenticationProvider(authenticationProvider())
.httpBasic()
//未登录时
.authenticationEntryPoint((request,response,authException) -> {
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
RespBean error = RespBean.error("未登录");
String s = new ObjectMapper().writeValueAsString(error);
out.write(s);
out.flush();
out.close();
})
.and()
.authorizeRequests()
.anyRequest().authenticated() //必须授权才能范围
.and()
.formLogin() //使用自带的登录
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
//登录失败,返回json
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException exception) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter out = resp.getWriter();
RespBean respBean = RespBean.error("登录失败!");
if (exception instanceof UsernameNotFoundException || exception instanceof BadCredentialsException) {
respBean.setMsg("用户名或者密码输入错误,请重新输入!");
} else if (exception instanceof DisabledException) {
respBean.setMsg("账户被禁用");
} else {
respBean.setMsg("未知错误");
}
out.write(objectMapper.writeValueAsString(respBean));
out.flush();
out.close();
}
})
//登录成功,返回json
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Student student = (Student) authentication.getPrincipal();
student.setPassword(null);
RespBean ok = RespBean.ok("登录成功!", student);
String s = new ObjectMapper().writeValueAsString(ok);
out.write(s);
out.flush();
out.close();
}
})
.and()
.exceptionHandling()
//没有权限,返回json
.accessDeniedHandler((request,response,ex) -> {
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(RespBean.error("权限不足")));
out.flush();
out.close();
})
.and()
.logout()
//退出成功,返回json
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write(new ObjectMapper().writeValueAsString(RespBean.ok("注销成功!")));
out.flush();
out.close();
}
})
.permitAll();
//开启跨域访问
http.cors().disable();
//开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误
http.csrf().disable();
}
@Override
public void configure(WebSecurity web) {
//对于在header里面增加token等类似情况,放行所有OPTIONS请求。
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**");
}
}
四、mapper层
mapper下的StudentMapper.java
/**
* @author xiao
*/
public interface StudentMapper {
Student loadUserBySno(String sno);
}
resource下的StudentMapper.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.jxnu.os.mapper.StudentMapper">
<resultMap id="BaseResultMap" type="com.jxnu.os.model.Student">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="sno" property="sno" jdbcType="VARCHAR"/>
<result column="s_sex" property="s_sex" jdbcType="CHAR"/>
<result column="t_id" property="t_id" jdbcType="INTEGER"/>
<result column="password" property="password" jdbcType="VARCHAR"/>
</resultMap>
<select id="loadUserByUsername" resultMap="BaseResultMap">
select * from student where username=#{username}
</select>
</mapper>
五、model层
model下的Student.java
注意一定要implements UserDetails
/**
* @author xiao
* 学生实体类
*/
public class Student implements UserDetails {
//
//学生主键ID
private Integer id;
//学生姓名
private String username;
//登录密码
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
private Collection<? extends GrantedAuthority> authorities;
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
六、service层
service下的StudentService.java
/**
* @author xiao
*/
@Service
public class StudentService implements UserDetailsService {
@Autowired
StudentMapper studentMapper;
/**
* 登录
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Student student = studentMapper.loadUserBySno(username);
if (student == null) {
throw new UsernameNotFoundException("用户不存在");
}
return student;
}
}