SpringSecurity前后端分离的使用

1 说明

使用SpringSecurity实现安全认证,使用模拟redis的缓存机制,实现不同权限的登录设置。

1.1 用户信息

用户编号用户名密码权限
1zhangsan123456
2lisi123456admin、expert

1.2 路由信息

路由权限备注
/security/login所有人都有权限
/security/adminadmin、expert登录以后的用户,必须含有admin、expert权限,才能访问
其他账号和密码登录登录以后的用户才能访问,例如:”/security/test”、“/security/logout”

2 工程布局

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qNcVoWGz-1657193532083)(SpringSecurity前后端分离的使用.assets/image-20220707184631126.png)]

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

}
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值