SpringSecurity前后端分离的使用

SpringBoot_整合SpringSecurity(前后端分离版) 1、登录校验流程2、SpringSecurity简单过滤器链(完整的过滤器大概是14个),前后端分离一般用jwt,前后端不分离一般采用session。 阅读详情

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

}
Springboot +spring security,前后端分离时的security处理方案(一) 阅读详情

相关推荐

SpringSecurity前后端分离

继承了抽象类,抽象类实现了接口认证流程1、前端通过把用户名和密码发送到后端的控制器,控制器调用业务层2、Service层创建对象,把用户名和密码封装成对象3、然后调用的方法进行认证,抽象类中重写了方法4、的方法中调用了抽象方法方法5、在重写方法里调用了方法,自定义类实现接口,重写方法6、在方法中,会查询用户和角色,然后返回对象实现CommonResp接口,方便自定义异常后续修改错误信息//直接接收RespBeanEnum的传参用于构造业务异常super();//调用父类的无参构造方法。...

m0_67393039的博客 1032

SpringBoot+Security+Vue前后端分离开发权限管理系统

适用人群所有的IT从业者,尤其适合快速掌握新技术,快速增长工作经验人群,对教育公平,教育公益,教育爱心公益人士课程概述该互联网实战项目是基于 Spring Boot 2+ SpringSecurity5+Element UI+Vue Admin Template+蚂蚁可视化AntV 等技术栈开发的项目,采用分布式,多模块,前后端分离开发。包括图形展示、权限管理、用户管理等功能。【后端技术】技术说明Spring Boot2MVC框架 开发的一站式解决方案Spring Security5 认证和授权框架MyBatisPlus3.3.1 基于 MyBatis 框架的快速研发框架MyBatisCode工具生成 MyBatis 相关代码Jackson提供了处理 JSON 数据的工具Lombok简化对象封装工具 Druid   数据库连接池 【前端技术】Vue       互联网最火的前端框架Vue Router路由框架Vuex全局状态管理框架Axios前端 HTTP 框架Element UI前端 UI 框架Vue Element Admin前端模板Antv  蚂蚁金服可视化技术,阿里巴巴可视化技术,天猫,淘宝,支付宝,花呗均使用AntV【开发工具】IntelliJ IDEA开发 IDESQLyog数据库连接客户端PostmanHTTP 请求工具【开发环境】工具版本JDK1.8MySQL5.7

基于SpringSecurity 的登录详解(前后端分离)

前后端分离登录:JWT单点登录

qq_45784240的博客 5055

使用JWT的SpringSecurity实现前后端分离

JWT,前后端分离,SpringSecurity

qq_59099003的博客 1445

springsecurity完成前后端完全分离

Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519).该token被设计为紧凑且==安全==的,特别适用于==分布式站点的单点登录(SSO)场景==。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

z2331198564653的博客 1643

SpringSecurity前后端分离登录认证

新增接口:@Autowiredreturn new Result(200,"登陆成功",loginService.login(user));}}@Overridehttp//关闭csrf//不通过Session获取SecurityContext.and()// 对于登录接口 允许匿名访问// 除上面外的所有请求全部需要鉴权认证}配置redis:spring:redis:port: 6379认证逻辑:将注入到容器中@Bean@Override}

m0_67401153的博客 1173

SpringSecurity(前后端分离)

​是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。​ 一般来说中大型的项目都是使用来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro的上手更加的简单。​ 一般Web应用的需要进行认证和授权。​认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户​授权:经过认证后判断当前用户是否有权限进行某个操作​ 而认证和授权也是SpringSecurity作为安全框架的核心功能。

m0_70819033的博客 1534

手把手带你入门 前后端分离整合SpringSecurity,Vue整合SpringSecurity

简单的前后端分离整合SpringSecurity 推荐学习地址:https://blog.youkuaiyun.com/u012702547/article/details/79019510 在普通的项目中使用SpringSecurity比较简单,但是在前后端分离的项目中使用SpringSecurity就比较复杂了 总体步骤: 创建简易的数据库(用户表、权限表等) 创建一个简单的Vue登录页面 编写实体类 编写登录的dao、service等 在Controller中编写一个@GetMapping("

qq_41498751的博客 941

SpringSecurity + JWT(前后端分离)

想必大四的小伙伴们陆陆续续开始写毕业设计了,对于网络安全框架SpringSecurity在网上的资源都是前后端不分离的,这里记录一下小伟的前后端分离版。

HGW的博客 6295

硬件级Dalvik字节码粒度无痕HOOK及VMP取址码定位分析

2.通过硬件读写断点的输出信息 可知pc寄存器就是art解释器的取码地址 直接硬件执行断点在这个pc 即可直接trace所有的smali执行流 通杀所有机型系统。本文即将探讨的是 如何在硬件级别实现dalvik bytecode粒度的无痕拦截技术 并实现鼠标点击一键hook 指哪儿打哪儿 感受 button power 的强大魅力!4.由于硬件断点是同步的 断下后可随时硬件dump下这一瞬间的app内存映像 写入unicorn的内存模拟执行。解释器在解释执行前必会读取内存中的bytecode。

2503_90751789的博客 1085

从BIOS到路由器:深入拆解SPI NOR Flash的硬件连接与‘芯片内执行’(XIP)奥秘

本文深入解析SPI NOR Flash的硬件连接与‘芯片内执行’(XIP)技术,从BIOS到路由器的应用场景出发,详细介绍了其架构精髓、典型连接方案、时序设计及性能优化方法。通过实际案例和参数对比,帮助开发者掌握NOR Flash在嵌入式系统中的关键作用与设计技巧,提升电路设计效率与可靠性。

weixin_30522183的博客 492

SpringSecurity如何实现前后端分离

由于前端直接调用登录接口,跳过了获取登录页面的步骤,所以服务端没有机会将CSRF Token传给前段,所以要把POST /login接口的CSRF校验剔除掉。

xsgnzb的专栏 2301

Simulink/Requirements Toolbox 学习(一):概述

编写、导入、导出需求并使需求正式化;两种创建需求的模块:需求编辑器、需求透视;描述需求的方式:文本、图像和关键字;通过导入和导出需求文件,与第三方需求管理工具(例如 Microsoft Word、Microsoft Excel®、IBM DOORS和 IBM DOORS Next)集成。涉及模块:Requirements Eidtor、Requirements Table等;

855

SpringSecurity——前后端分离登录认证

在 Spring Security 中,退出操作(logout)的设计逻辑与登录有所不同。登录过程涉及用户凭证验证、状态检查和密码匹配等环节,这些都有可能失败,所以需要提供失败处理器(如登录失败处理器)。前后端分离:Nginx 【Vue】 <----jwt----> Tomcat 【 (controller、sucurity) 】三个里面有任何一个不同,都是跨域,跨域是浏览器不允许的,浏览器是为了安全,不允许你跨域访问。从数据库中加载用户信息,返回一个包含用户状态和权限信息的。service实现类。

gege_0606的博客 1453

Ubuntu服务器通过IPV6端口转发搭建幻兽帕鲁私服实战

本文详细介绍了在Ubuntu服务器上通过IPV6端口转发搭建幻兽帕鲁私服的完整教程。针对只有公网IPV6地址的服务器环境,提供了从硬件检查、端口转发工具配置到游戏服务器安装的全流程解决方案,帮助玩家轻松实现多人联机游戏体验。

weixin_30652491的博客 490

【ComfyUI】【Nunchaku】【diffusers报错解决】秋叶整合包安装 Nunchaku 报错的解决方法

最近在折腾 AI 绘图时,我尝试在秋叶的 ComfyUI 整合包中安装 `ComfyUI-nunchaku` 插件(版本 0.3.3),结果启动后直接报错,提示无法从 `accelerate.utils.memory` 中导入 `clear_device_cache`,让我一度怀疑插件是否兼容。查阅了一堆 issue 和源码之后,总算找到了原因和解决方法。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1856

SpringSecurity实现前后端分离登录授权详解

SpringSecurity java Springboot

qq_43649937的博客 5263

亚马逊跨境电商选品数据分析:Python爬虫实战指南

本文将带领大家构建一套完整的亚马逊选品数据采集与分析系统,使用最新的Python技术栈,从零开始爬取亚马逊商品数据,并进行深度分析。

2201_76125261的博客 299

SpringSecurity前后端分离自定义登录处理

SpringSecurity前端后分离自定义登录处理

z318913的博客 3917

zemax 如何编译用户自定义DLL(含VS下载教程)

zemax 如何编译用户自定义DLL(含VS下载教程)

weixin_72050316的博客 492

SerDes电路的PCB仿真设计规则及策略

SerDes的PCB设计中,重点工作是使用3D 电磁 (EM) 场求解器,进行过孔结构优化,包括 BGA的扇入和扇出区域以及布线的过孔区域,并且,利用连接器供应商提供加密的 3D 模型,进行连接器和 PCB 的级联仿真,最终获取系统级的通道性能参数,如插入损耗、回波损耗、串扰和模式转换、阻抗曲线等,如果发现任何缺陷,再进行进一步优化,这一过程中,推荐进行拆分仿真,以提高设计效率。

一只豌豆象的博客 2192

SpringSecurity前后端分离(包含token和验证码登录)

实现从数据库中获取用户的信息,自定义登录逻辑@Service@Autowired@Autowired@Autowired@Autowired@Override//需要构造出 org.springframework.security.core.userdetails.User 对象并返回/*** String username:用户名* String password: 密码* boolean enabled: 账号是否可用。

qq_57907966的博客 6068

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

SpringSecurity前后端分离代码

/ JsonInclude.Include.NON_NULL 的意义是只有当属性的值不为 null 时,该属性才会被包含在生成的JSON对象中。// 如果你的Java对象有一些字段值为 null,在将这个对象转换为JSON字符串时,这些 null 的字段将不会出现在最终的JSON输出里。// @JsonInclude 控制JSON序列化时哪些属性会被包含在输出的JSON字符串中。创建好的初始目录,直接将 demos 包删除。登陆在servixe的接口。用户表(User)实体类。webutils的工具类。

qq_70786441的博客 992

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

前后端分离下的-SpringSecurity

前后端分离下的SpringBoot踩坑配置

coder-itl 1410

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

上一篇: Spring Boot使用log4j2管理日志
下一篇: Linux中文本处理命令
MasonYyp
博客等级 码龄9年 301粉丝 297原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值