pom檔案
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 實作對 Spring Security 的自動化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
前後端分離,後端不幹涉前端的跳轉,采用json格式傳遞資料
WebSecurityConfigurerAdapter 配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailService myUserDetailService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Autowired
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Autowired
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailService).passwordEncoder(passwordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//退出
http.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(myLogoutSuccessHandler);
// 未登入&無權限傳回
http.exceptionHandling()
.authenticationEntryPoint(myAuthenticationEntryPoint);
// 登入
http.formLogin().loginProcessingUrl("/login")
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAuthenticationFailureHandler)
.and().authorizeRequests()
.antMatchers("/","/login.html").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();//關閉csrf防護
}
}
AuthenticationSuccessHandler
- 登入成功
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", authentication.getPrincipal()); // 登入成功的對象
out.write(objectMapper.writeValueAsString(map));
out.flush();
out.close();
}
}
AuthenticationFailureHandler
- 登入失敗
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 401);
if (exception instanceof LockedException) {
map.put("msg", "賬戶被鎖定,登入失敗!");
} else if (exception instanceof BadCredentialsException) {
map.put("msg", "使用者名或密碼輸入錯誤,登入失敗!");
} else if (exception instanceof DisabledException) {
map.put("msg", "賬戶被禁用,登入失敗!");
} else if (exception instanceof AccountExpiredException) {
map.put("msg", "賬戶過期,登入失敗!");
} else if (exception instanceof CredentialsContainer) {
map.put("msg", "密碼過期,登入失敗");
} else {
map.put("msg", "登入失敗!");
}
out.write(objectMapper.writeValueAsString(map));
out.flush();
out.close();
}
}
LogoutSuccessHandler
- 登出成功
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "登出登入成功!");
out.write(objectMapper.writeValueAsString(map));
out.flush();
out.close();
}
}
AuthenticationEntryPoint
- 認證失敗
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Autowired
private ObjectMapper objectMapper;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
// response.sendError(HttpServletResponse.SC_UNAUTHORIZED,authException.getMessage());
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
Map<String,Object> map = new HashMap<String,Object>();
map.put("code",403);
map.put("message","未登入或無權限");
out.write(objectMapper.writeValueAsString(map));
out.flush();
out.close();
}
}
UserDetailsService
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return new User("user",passwordEncoder.encode("123"),new ArrayList<>());
}
}
PasswordEncoder
@Component
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return encode(charSequence).equals(s);
}
}