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;
}
}