1 说明
使用SpringSecurity实现安全认证,使用模拟redis的缓存机制,实现不同权限的登录设置。
1.1 用户信息
用户编号 | 用户名 | 密码 | 权限 |
---|---|---|---|
1 | zhangsan | 123456 | |
2 | lisi | 123456 | admin、expert |
1.2 路由信息
路由 | 权限 | 备注 |
---|---|---|
/security/login | 所有人都有权限 | |
/security/admin | admin、expert | 登录以后的用户,必须含有admin、expert权限,才能访问 |
其他 | 账号和密码登录 | 登录以后的用户才能访问,例如:”/security/test”、“/security/logout” |
2 工程布局
3 源代码
注:application.yml文件没有添加内容。
3.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>security</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Init the entity -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- 常用工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.22</version>
</dependency>
<!-- 引入SpringSecurity -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 生成jwt工具包 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.1.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
3.2 config包
3.2.1 WebSecurityConfig
安全配置
package com.example.security.config;
import com.example.security.filter.AuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// 自动调用config.UserDetailsServiceImp
// 按照byType注入
@Autowired
private UserDetailsService userDetailsService;
// 设置权限
@Autowired
private AccessDeniedHandler accessDeniedHandler;
// 未登录
@Autowired
private AuthenticationEntryPoint authEntryPoint;
@Autowired
private AuthenticationTokenFilter authenticationTokenFilter;
// 将BCryptPasswordEncoder对象注入Spring容器中,
// SpringSecurity会使用PasswordEncoder自动密码校验
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
// 用户权限管理器,进行用户认证,配置用户签名服务和用户权限控制
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// 用户认证,配置用户签名服务和用户权限控制
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 会自动调用UserDetailsServiceImp下的loadUserByUsername()方法
auth.userDetailsService(this.userDetailsService).passwordEncoder(this.passwordEncoder());
}
// 用户授权,配置拦截请求、请求验证、异常处理
@Override
protected void configure(HttpSecurity http) throws Exception {
// 不通过Session获取SecurityContext
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//关闭csrf
http.csrf().disable();
// 解决跨域
http.cors();
// 未登录
http.exceptionHandling().authenticationEntryPoint(authEntryPoint);
// 设置权限,对应hasAnyAuthority
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
// 设置认证的action
http.authorizeRequests()
// 不拦截以下action
.antMatchers("/security/login").permitAll()
// 具有admin和expert权限的可以访问此路径
.antMatchers("/security/admin").hasAnyAuthority("admin", "expert")
// 处了上面的action,都需要鉴权认证
.anyRequest().authenticated();
// 设置过滤器
http.addFilterBefore(this.authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
}
3.2.2 UserDetailsServiceImp
用户登录认证
package com.example.security.config;
import com.example.security.dao.UserInfoDao;
import com.example.security.entity.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
@Component
public class UserDetailsServiceImp implements UserDetailsService {
@Autowired
private UserInfoDao userInfoDao;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
// 根据用户名获取用户的权限信息
UserInfo userInfo = this.userInfoDao.getUserInfo(userName);
return userInfo;
}
}
3.2.3 AuthenticationEntryPointImp
用户登录状态认证
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class AuthenticationEntryPointImp implements AuthenticationEntryPoint {
@Autowired
private ObjectMapper objectMapper;
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(objectMapper.writeValueAsString("No login"));
out.flush();
out.close();
}
}
3.2.4 AccessDeniedHandlerImp
用户鉴权
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class AccessDeniedHandlerImp implements AccessDeniedHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(objectMapper.writeValueAsString("No access"));
out.flush();
out.close();
}
}
3.3 filter包下AuthenticationTokenFilter
用户token权限过滤器,登录完成后调用。
package com.example.security.filter;
import com.auth0.jwt.interfaces.Claim;
import com.example.security.dao.CacheDao;
import com.example.security.util.JwtUtil;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@Component
public class AuthenticationTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
// 获取请求头中的token
String token = httpServletRequest.getHeader("token");
if(StringUtils.isEmpty(token)){
// 没有携带token,传递给Security验证
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
// 验证token是否合法
Map<String, Claim> userInfoMap = JwtUtil.parseToken(token);
if(userInfoMap == null){
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
String userId = String.valueOf(userInfoMap.get("userid"));
// 判断token是否在缓存中,实际中可使用redis替代
boolean isExistToken = false;
// 设置权限,从缓存中获取用户信息
List<GrantedAuthority> authorityList = null;
for (Map<String, Object> item: CacheDao.userInfoList) {
if(item.get("token").equals(token)){
isExistToken = true;
authorityList = (List<GrantedAuthority>) item.get("authority");
break;
}
}
if(!isExistToken){
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
// 验证id,并设置权限
// 注意:此处是为了通过检验,不能添加密码
Authentication authentication = new UsernamePasswordAuthenticationToken(userId,null, authorityList);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 放行action
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
3.4 util包下JwtUtil
实现token的创建和解析。
package com.example.security.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
// 签名
private static final String sign = "security";
/**
* 生成token
* @param userId 用户编号
* @return 返回含有数字签名的token值
*/
public static String createToken(String userId){
Map<String, Object> map = new HashMap<>();
map.put("algorithm", "HS256");
map.put("type", "JWT");
// 设置过期时间为1天
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE,1);
return JWT.create()
// 设置header
.withHeader(map)
// 设置用户信息,可根据实际情况进行修改
.withClaim("userid", userId)
// 可以添加多个用户信息
// .withClaim("username", username)
// 设置过期时间,如果用redis可以不设置
.withExpiresAt(instance.getTime())
// 设置签发时间
.withIssuedAt(new Date())
// 设置签名
.sign(Algorithm.HMAC256(sign));
}
/**
* 解析token
* @param token 上面生成的含有数字签名的token值
* @return 返回token中声明的用户信息
*/
public static Map<String, Claim> parseToken(String token){
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(sign)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
return null;
}
// 获取声明的信息
return jwt.getClaims();
}
}
3.5 entity包下UserInfo
实现UserDetails接口的用户信息,提供给UserDetailsServiceImp类使用
package com.example.security.entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
// 此处,将用户的信息和权限放在一起
public class UserInfo implements UserDetails {
// 用户基本信息
private String id;
private String username;
private String password;
private Collection<? extends GrantedAuthority> authorities;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String getUsername() {
return this.username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String getPassword() {
return this.password;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
// 注意:下面的返回值必须都是true
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
3.6 controller包下的SecurityController
package com.example.security.controller;
import com.example.security.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/security")
@ResponseBody
public class SecurityController {
@Autowired
private LoginService loginService;
@PostMapping("/login")
public String login(String name, String pwd){
return this.loginService.login(name, pwd);
}
@PostMapping("/logout")
public String logout(String name, String pwd){
return this.loginService.logout(name, pwd);
}
@PostMapping("/test")
public String test(){
return "test";
}
@PostMapping("/admin")
public String admin(){
return "admin";
}
}
3.7 service包下的LoginService
package com.example.security.service;
import com.example.security.dao.CacheDao;
import com.example.security.entity.UserInfo;
import com.example.security.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class LoginService {
// 调用WebSecurityConfig中的authenticationManagerBean方法返回值
@Autowired
private AuthenticationManager authenticationManager;
public String login(String name, String pwd) {
// 设置登录的验证信息
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(name, pwd);
/*
* (1)自动调用UserDetailsService接口的实现类UserDetailsServiceImp;
* (2)自动验证UserDetailsServiceImp类中loadUserByUsername方法的返回值UserDetails接口的实现类UserInfo;
* (3)鉴权失败,返回403
*/
Authentication authentication = null;
try {
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = this.authenticationManager.authenticate(usernamePasswordAuthenticationToken);
} catch (Exception e) {
System.out.println("账号或密码错误!");
}
if(authentication != null){
// 获取用户信息
UserInfo userInfo = (UserInfo) authentication.getPrincipal();
System.out.println(userInfo.getId()+" "+userInfo.getUsername());
// 生成token
String token = JwtUtil.createToken(userInfo.getId());
// 将用户信息添加到缓存中,可用redis替代
// 注意:此处的信息会在filter中用到
Map<String, Object> cacheUserInfo = new HashMap<>();
cacheUserInfo.put("token", token);
cacheUserInfo.put("authority", userInfo.getAuthorities());
CacheDao.userInfoList.add(cacheUserInfo);
return token;
}else {
System.out.println("登录失败!");
return "-1";
}
}
// 退出
public String logout(String name, String pwd){
return "logout";
}
}
3.8 dao包
模拟数据库
3.8.1 UserInfoDao
模拟数据库数据
package com.example.security.dao;
import com.example.security.entity.UserInfo;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Repository
public class UserInfoDao {
// 模拟从数据库中获取用户信息
public UserInfo getUserInfo(String userName){
// 模拟数据库中的用户信息
List<UserInfo> userInfoList = new ArrayList<>();
// 密码是 1223456
// 注意:此处密码必须使用BCryptPasswordEncoder加密
UserInfo userInfo = new UserInfo();
userInfo.setId("1");
userInfo.setUsername("zhangsan");
userInfo.setPassword("$2a$10$csDT9rGTLPtFkMg7OgMsuOOrPQ8wmRlb2fPlGJBi/lz0bR.MfKPKG");
userInfo.setAuthorities(new ArrayList<>());
userInfoList.add(userInfo);
userInfo = new UserInfo();
userInfo.setId("2");
userInfo.setUsername("lisi");
userInfo.setPassword("$2a$10$csDT9rGTLPtFkMg7OgMsuOOrPQ8wmRlb2fPlGJBi/lz0bR.MfKPKG");
userInfo.setAuthorities(new ArrayList<>(Arrays.asList(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("expert"))));
userInfoList.add(userInfo);
// 查找用户信息
for (UserInfo userInfoItem: userInfoList ) {
if(userInfoItem.getUsername().equals(userName)){
return userInfoItem;
}
}
return null;
}
}
3.8.2 CacheDao
模拟redis缓存
package com.example.security.dao;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CacheDao {
public static List<Map<String, Object>> userInfoList = new ArrayList<>();
}
3.9 SecurityApplication
package com.example.security;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class, args);
}
}
4 截图
4.1 使用账号zhangsan访问
(1) 不登录访问“/security/test”路由
(2) 用户登录
(3) 在head中携带token再次访问“/security/test”路由
(4) 账号zhangsan访问“/security/admin”
4.2 使用账号lisi访问
先使用账号lisi登录,再使用token访问“/security/admin”
5 其他
上面的内容,针对前后端分离的项目已经基本够用,如果不是前后端分离的项目可以自定义登出、登录成功、登录失败。
5.1 WebSecurityConfig配置
package com.example.security.config;
import com.example.security.filter.AuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// 自动调用WebSecurityUserDetailsService
// 按照byType注入
@Autowired
private UserDetailsService userDetailsService;
// 设置权限
@Autowired
private AccessDeniedHandler accessDeniedHandler;
// 未登录
@Autowired
private AuthenticationEntryPoint authEntryPoint;
// 登录成功
@Autowired
private AuthenticationSuccessHandler authSuccessHandler;
// 登录失败
@Autowired
private AuthenticationFailureHandler authFailureHandler;
// 设置登出
@Autowired
private LogoutSuccessHandler logoutSuccessHandler;
@Autowired
private AuthenticationTokenFilter authenticationTokenFilter;
// 将BCryptPasswordEncoder对象注入Spring容器中,
// SpringSecurity会使用PasswordEncoder自动密码校验
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
// 用户权限管理器,进行用户认证,配置用户签名服务和用户权限控制
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// 用户认证,配置用户签名服务和用户权限控制
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.userDetailsService).passwordEncoder(this.passwordEncoder());
}
// 用户授权,配置拦截请求、请求验证、异常处理
@Override
protected void configure(HttpSecurity http) throws Exception {
// 不通过Session获取SecurityContext
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//关闭csrf
http.csrf().disable();
// 解决跨域
http.cors();
// 未登录
http.exceptionHandling().authenticationEntryPoint(authEntryPoint);
// 此处没有使用系统默认的login,可以不设置
// 登录,此处可以不设置,默认会跳转到SpringSecurity的登录页面
http.formLogin()
//登录失败处理
.failureHandler(authFailureHandler)
//登录成功处理
.successHandler(authSuccessHandler);
// 退出登录
http.logout().logoutSuccessHandler(logoutSuccessHandler).permitAll();
// 设置权限,对应hasAnyAuthority
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
// 设置认证的action
http.authorizeRequests()
// 不拦截以下action
.antMatchers("/security/login").permitAll()
// 具有admin和expert权限的可以访问此路径
.antMatchers("/security/admin").hasAnyAuthority("admin", "expert")
// 处了上面的action,都需要鉴权认证
.anyRequest().authenticated();
// 设置过滤器
http.addFilterBefore(this.authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
}
5.2 登出
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class LogoutSuccessHandlerImp implements LogoutSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(objectMapper.writeValueAsString("Logout success"));
out.flush();
out.close();
}
}
5.3 登录成功
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class AuthenticationSuccessHandlerImp implements AuthenticationSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
AuthenticationSuccessHandler.super.onAuthenticationSuccess(request, response, chain, authentication);
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(objectMapper.writeValueAsString("login success"));
out.flush();
out.close();
}
}
5.4 登录失败
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class AuthenticationFailureHandlerImp implements AuthenticationFailureHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(objectMapper.writeValueAsString("login failure"));
out.flush();
out.close();
}
}