优化网站除了百度站长,南京装修公司做网站,山西晋中网站建设,网站建设推广唯心cidun8前言
Spring Security 是一款强大且高度可定制的认证和访问控制框架#xff0c;它是为了保护基于Spring的应用程序提供安全性支持。Spring Security提供了全面的安全服务#xff0c;主要针对企业级应用程序的需求。其核心组件主要包含#xff1a;Authentication#xff08…前言
Spring Security 是一款强大且高度可定制的认证和访问控制框架它是为了保护基于Spring的应用程序提供安全性支持。Spring Security提供了全面的安全服务主要针对企业级应用程序的需求。其核心组件主要包含Authentication认证、Authorization授权、Principal主体、Granted Authority授予的权限、Security Context安全上下文可提供方法级别的权限认证。其底层主要通过Filter拦截器实现关于其实现原理我们会在后面的章节内容中介绍。
本节内容主要是关于前后端分离的项目如何集成spring securtity安全框架完成用户的认证与授权。也会详细介绍各个配置项及配置组件的使用。
正文
①创建一个springboot web项目引入spring security的依赖同时引入mysql和mybatis-plus依赖用于实现一个数据库版本的spring security安全框架 dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion2.0.22/version
/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.4/version
/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId
/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope
/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional
/dependency ②在application.yml中添加数据库配置用于连接数据库
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.110.88:3306/ht-atp?characterEncodingutf-8serverTimezoneGMT%2B8useAffectedRowstruenullCatalogMeansCurrenttrueusername: rootpassword: root
server:port: 8080
③ 创建一张用户数据库表auth_user用于存储用户信息
CREATE TABLE auth_user (id int NOT NULL AUTO_INCREMENT,username varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,password varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL,enabled tinyint(1) NOT NULL,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT5 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci;
④创建用户实体AuthUser
Data
public class AuthUser {TableId(value id, type IdType.AUTO)private Integer id;private String username;private String password;private Boolean enabled;} ⑤创建用户持久层Mapper
package com.yundi.atp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yundi.atp.entity.AuthUser;
import org.apache.ibatis.annotations.Mapper;Mapper
public interface AuthUserMapper extends BaseMapperAuthUser {}⑥统一响应请求返回定义
package com.yundi.atp.commom;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;Data
Builder
public class ApiResponseT {Schema(name code, description 状态码)private Integer code;Schema(name msg, description 消息结果)private String msg;Schema(name data, description 数据)private T data;/*** 成功统一响应格式** param* param T* return*/public static T ApiResponseT success() {ApiResponseT apiResponse new ApiResponse(200, 成功, null);return apiResponse;}/*** 成功统一响应格式** param* param T* return*/public static T ApiResponseT success(String msg) {ApiResponseT apiResponse new ApiResponse(200, msg, null);return apiResponse;}/*** 成功统一响应格式** param data* param T* return*/public static T ApiResponseT success(T data) {ApiResponseT apiResponse new ApiResponse(200, 成功, data);return apiResponse;}/*** 成功统一响应格式** param data* param T* return*/public static T ApiResponseT success(String msg, T data) {ApiResponseT apiResponse new ApiResponse(200, msg, data);return apiResponse;}/*** 失败统一响应格式** param code* param message* param T* return*/public static T ApiResponseT fail(Integer code, String message) {return new ApiResponse(code, message, null);}/*** 失败统一响应格式** param errorCode* param T* return*/public static T ApiResponseT fail(ErrorCode errorCode) {return new ApiResponse(errorCode.getCode(), errorCode.getMsg(), null);}
}⑦ 统一错误码定义
package com.yundi.atp.commom;public enum ErrorCode {SYSTEM_ERROR(10000, 系统错误!),UN_AUTH(10001, 用户未认证请先登录),AUTH_FAILURE(10002, 认证失败用户名或密码错误),UN_ACCESS(10003, 该用户没有此操作权限),METHOD_ARGS_VALID(10004, 方法参数验证失败),TOKEN_VALID(10005, token鉴权失败),TOKEN_NOT_EXIST(10006, token不存在),;private Integer code;private String msg;ErrorCode(Integer code, String message) {this.code code;this.msg message;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg msg;}
}⑧创建DbUserDetailsManager类实现UserDetailsManager和UserDetailsPasswordService接口方法用于实现数据库版本的认证权限管理该类主要是实现用户数据和权限数据的获取用于认证和授权使用
package com.yundi.atp.auth;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yundi.atp.entity.AuthUser;
import com.yundi.atp.mapper.AuthUserMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;Service
public class DbUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {Resourceprivate AuthUserMapper authUserMapper;Overridepublic UserDetails updatePassword(UserDetails user, String newPassword) {return null;}Overridepublic void createUser(UserDetails userDetails) {AuthUser authUser new AuthUser();authUser.setUsername(userDetails.getUsername());authUser.setPassword(userDetails.getPassword());authUser.setEnabled(true);authUserMapper.insert(authUser);}Overridepublic void updateUser(UserDetails user) {}Overridepublic void deleteUser(String username) {}Overridepublic void changePassword(String oldPassword, String newPassword) {}Overridepublic boolean userExists(String username) {return false;}Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询用户数据QueryWrapperAuthUser queryWrapper new QueryWrapper();queryWrapper.eq(username, username);AuthUser authUser authUserMapper.selectOne(queryWrapper);if (authUser null) {throw new UsernameNotFoundException(username);} else {//从数据库获取用户权限列表CollectionGrantedAuthority authorities new ArrayList();authorities.add(() - USER_LIST);authorities.add(() - USER_ADD);return new User(//用户账号authUser.getUsername(),//用户密码authUser.getPassword(),//是否启用authUser.getEnabled(),//用户账号是否过期true,//用户凭证是否过期true,//用户是否未被锁定true,//权限列表authorities);}}
}⑨创建MyAuthenticationEntryPoint类实现AuthenticationEntryPoint接口用于未认证的处理
package com.yundi.atp.auth;import com.alibaba.fastjson.JSON;
import com.yundi.atp.commom.ApiResponse;
import com.yundi.atp.commom.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;Slf4j
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {log.info(未认证 authException);//返回响应response.setContentType(application/json;charsetUTF-8);response.getWriter().println(JSON.toJSONString(ApiResponse.fail(ErrorCode.UN_AUTH)));}
}⑩创建MyAuthenticationSuccessHandler类实现AuthenticationSuccessHandler接口用于认证成功的处理
package com.yundi.atp.auth;import com.alibaba.fastjson.JSON;
import com.yundi.atp.commom.ApiResponse;
import com.yundi.atp.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;Slf4j
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {AuthenticationSuccessHandler.super.onAuthenticationSuccess(request, response, chain, authentication);}Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {//返回响应response.setContentType(application/json;charsetUTF-8);response.getWriter().println(JSON.toJSONString(ApiResponse.success(认证成功)));}
}⑪创建MyAuthenticationFailureHandler类实现AuthenticationFailureHandler接口用于认证失败的处理
package com.yundi.atp.auth;import com.alibaba.fastjson.JSON;
import com.yundi.atp.commom.ApiResponse;
import com.yundi.atp.commom.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;Slf4j
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {response.setContentType(application/json;charsetUTF-8);response.getWriter().println(JSON.toJSONString(ApiResponse.fail(ErrorCode.AUTH_FAILURE)));}
}⑫创建MyLogoutSuccessHandler类实现LogoutSuccessHandler接口用于退出登录的处理
package com.yundi.atp.auth;import com.alibaba.fastjson.JSON;
import com.yundi.atp.commom.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;Slf4j
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {response.setContentType(application/json;charsetUTF-8);response.getWriter().println(JSON.toJSONString(ApiResponse.success(注销成功)));}
}⑬创建MyAccessDeniedHandler类实现AccessDeniedHandler接口用于授权不通过的处理
package com.yundi.atp.auth;import com.alibaba.fastjson.JSON;
import com.yundi.atp.commom.ApiResponse;
import com.yundi.atp.commom.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;Slf4j
public class MyAccessDeniedHandler implements AccessDeniedHandler {Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {response.setContentType(application/json;charsetUTF-8);response.getWriter().println(JSON.toJSONString(ApiResponse.fail(ErrorCode.UN_ACCESS)));}
}⑭创建spring security的配置类开启spring security认证以及方法级别的授权
package com.yundi.atp.config;import com.yundi.atp.auth.*;
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.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.web.SecurityFilterChain;EnableMethodSecurity
Configuration
public class SpringSecurityConfig {Autowiredprivate DbUserDetailsManager dbUserDetailsManager;Beanpublic AuthenticationManager authenticationManager() {DaoAuthenticationProvider authenticationProvider new DaoAuthenticationProvider();authenticationProvider.setUserDetailsService(dbUserDetailsManager);authenticationProvider.setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());return new ProviderManager(authenticationProvider);}Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {//authorizeRequests()开启授权保护//anyRequest()对所有请求开启授权保护//authenticated()已认证请求会自动被授权http.authorizeRequests(authorize - {//放行路径authorize.antMatchers(/webjars/**, /v3/**, /doc.html, /favicon.ico, /swagger-ui/**).permitAll();//其它请求需要认证authorize.anyRequest().authenticated();});//自定义登录http.formLogin(formLogin - {formLogin.loginPage(/login).permitAll() //登录页面无需授权即可访问.usernameParameter(username) //自定义表单用户名参数默认是username.passwordParameter(password);//自定义表单密码参数默认是password//登录认证成功formLogin.successHandler(new MyAuthenticationSuccessHandler());//登录认证失败formLogin.failureHandler(new MyAuthenticationFailureHandler());});// 基本授权方式http.httpBasic(Customizer.withDefaults());//自定义注销http.logout(logout - {logout.logoutUrl(/logout);//删除授权信息logout.clearAuthentication(true);//删除cookielogout.deleteCookies(JSESSIONID);//设置session失效logout.invalidateHttpSession(true);//退出的处理logout.addLogoutHandler(new MyLogoutHandler());//退出成功的响应logout.logoutSuccessHandler(new MyLogoutSuccessHandler());});//错误处理http.exceptionHandling(exception - {//请求未认证的接口exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());//未授权的接口异常处理可能会不生效被全局异常处理器拦截exception.accessDeniedHandler(new MyAccessDeniedHandler());});// 跨域http.cors(Customizer.withDefaults());//关闭csrf攻击防御http.csrf(csrf - {csrf.disable();});return http.build();}}⑮spring security的配置说明 1.开启方法级别的权限验证 2.注入自定义的数据库版本的授权管理器 3.放行不需要认证的路径 4.配置登录的认证及认证处理 5.配置基本的授权方式 6.配置用户注销的处理 7.异常的处理 8.跨域的处理 9.关闭csrf攻击防御 ⑯使用PasswordEncoderFactories工厂生成一个spring security的密码创建一个用户用户测试 ⑰访问未认证的请求 ⑱使用正确的用户名和密码访问登录接口/login注意这里必须是post请求 ⑲使用错误的用户名和密码访问登录接口/login注意这里必须是post请求 ⑳测试接口授权目前的权限包含USER_LIST、USER_ADD在DbUserDetailsManager中查询的 ㉑访问/logout注销接口查看结果 结语
关于springboot前后端分离方式项目集成spring securtity安全框架的内容到这里就结束了我们下期见。。。。。。