自助建站竹子,杭州优化公司多少钱,网站建设与管理论文的总结,中小企业局域网组网方案目录
一、引言
1、什么是SpringSecurity认证
2、为什么使用SpringSecurity之认证
3、实现步骤
二、快速实现#xff08;案例#xff09;
1、添加依赖
2、配置
3、导入数据表及相关代码
4、创建登录页及首页
5、创建配置Controller
6、用户认证
6.1、用户对象User…目录
一、引言
1、什么是SpringSecurity认证
2、为什么使用SpringSecurity之认证
3、实现步骤
二、快速实现案例
1、添加依赖
2、配置
3、导入数据表及相关代码
4、创建登录页及首页
5、创建配置Controller
6、用户认证
6.1、用户对象UserDetails
6.2、业务对象UserDetailsService
6.3、SecurityConfig配置
7、启动测试
三、密码方式
1、自定义MD5加密
2、BCryptPasswordEncoder密码编码器
四、RememberMe
五、CSRF防御
1、什么是CSRF
2、SpringSecurity中如何使用CSRF 一、引言 1、什么是SpringSecurity认证 Spring Security认证是指基于Spring Security框架的身份验证过程。身份验证是指验证某个用户是否为系统中的合法主体即用户能否访问该系统。在Spring Security中通常要求用户提供用户名和密码进行认证。系统通过校验用户名和密码来完成认证过程。如果用户通过了身份验证他们就可以访问受保护的资源。Spring Security支持多种身份认证模式例如基于表单的身份认证、OpenID身份认证、Jasig中央认证服务等。 2、为什么使用SpringSecurity之认证
安全性Spring Security是一个成熟的安全框架提供了许多安全特性如身份验证、授权、密码加密等。它可以有效地保护应用程序的安全防止各种常见的安全威胁和漏洞。易于集成Spring Security与Spring框架深度集成可以方便地与Spring的其他功能配合使用如依赖注入、事务管理等。这使得在Spring环境下开发安全功能更加便捷。灵活性Spring Security提供了丰富的配置选项和扩展点可以根据具体需求进行灵活的定制。开发者可以根据应用程序的具体需求进行调整和优化。社区支持Spring Security拥有庞大的用户基础和活跃的社区可以提供丰富的支持和资源。在遇到问题时可以快速找到解决方案或寻求帮助。文档完善Spring Security的官方文档非常完善提供了详细的说明和示例可以帮助开发者快速上手并实现安全功能。
3、实现步骤
配置数据源提供用于存储用户名和密码的数据源例如数据库或LDAP服务器。配置认证模块配置身份验证模块以从数据源读取用户名和密码并验证它们是否匹配。配置授权模块配置授权模块以确定用户是否有权访问特定的资源。这通常基于角色或权限。配置安全配置类通过创建一个实现SecurityFilterChain接口的类配置Spring Security的过滤器链。在这个类中可以定义哪些URL需要身份验证和授权以及如何处理安全相关的异常。配置视图解析器配置视图解析器以将URL映射到相应的视图。在Spring Security中可以使用Thymeleaf或JSP等模板引擎来创建视图。 二、快速实现案例
1、添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-freemarker/artifactId
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scopeversion5.1.44/version
/dependency
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope
/dependency
dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.2/version
/dependency
dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-generator/artifactIdversion3.5.2/version
/dependency
dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion2.0.32/version
/dependency!-- security--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId
/dependency
2、配置
配置application.yml
server:port: 8080
spring:datasource:username: rootpassword: 1234url: jdbc:mysql://localhost:3306/vue?useUnicodetruecharacterEncodingutf8useSSLfalsedriver-class-name: com.mysql.jdbc.Driverfreemarker:enabled: truesuffix: .ftltemplate-loader-path: classpath:/templates/
mybatis-plus:# Mybatis Mapper所对应的XML位置mapper-locations: classpath:mapper/*.xml# 别名包扫描路径type-aliases-package: com.wfzldr.springsecurity01.model# 是否开启自动驼峰命名规则camel case映射configuration:map-underscore-to-camel-case: trueglobal-config:db-config:logic-delete-field: deleted # 全局逻辑删除的实体字段名logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
logging:level:com.wfzldr.springsecurity01.mapper: debug 3、导入数据表及相关代码
表名说明sys_user用户信息表sys_role角色信息表sys_module模块信息表权限信息表sys_user_role用户角色表sys_role_module角色模块表
sys_module sys_role sys_role_module sys_user sys_user_role 表之间的关系说明 生成对应表的代码层 4、创建登录页及首页
基于freemarker模板引擎创建登录页login.ftl和首页index.ftl。
login.ftl首页部分代码如下
h1用户登录/h1
form action/user/userLogin methodpostlabel账号/labelinput typetext nameusername/br/label密码/labelinput typepassword namepassword/br/input typesubmit value登 录/
/form
index.ftl代码如下
h1首页/h1
div styleposition: absolute;top:15px;right:15px;a href/logout安全退出/a/div href/logout为SpringSecurity配置的退出请求路径。主要完成以下几个操作 清除指定 CookieCookieClearingLogoutHandler#logout 清除 remember-mePersistentTokenBasedRememberMeServices#logout 使当前 Session无效清空当前的 SecurityContext 中认证用户信息 Authentication 5、创建配置Controller
创建IndexController配置跳转首页和登录页的接口。
Controller
public class IndexController {
RequestMapping(/)public String toLogin(){return login;}
RequestMapping(/index)public String toIndex(){return index;}
}
在UserController中配置请求登录接口
RestController
RequestMapping(/user)
public class UserController {
RequestMapping(/userLogin)public String userLogin(User user){return login;}} 6、用户认证
6.1、用户对象UserDetails
修改User并实现UserDetails。
Getter
Setter
TableName(sys_user)
public class User implements Serializable, UserDetails {...
/*** 用户权限集合* return*/Overridepublic Collection? extends GrantedAuthority getAuthorities() {return null;}
/*** 用户没过期返回true反之则false*/Overridepublic boolean isAccountNonExpired() {return true;}/*** 用户没锁定返回true反之则false*/Overridepublic boolean isAccountNonLocked() {return true;}/*** 用户凭据(通常为密码)没过期返回true反之则false*/Overridepublic boolean isCredentialsNonExpired() {return true;}/*** 用户是启用状态返回true反之则false*/Overridepublic boolean isEnabled() {return true;}
} UserDetails是Spring Security框架中的一个接口它代表了应用程序中的用户信息。UserDetails接口定义了一组方法用于获取用户的用户名、密码、角色和权限等信息以便Spring Security可以使用这些信息进行身份验证和授权。 以下是UserDetails接口中定义的方法 getUsername()获取用户的用户名。 getPassword()获取用户的密码。 getAuthorities()获取用户的角色和权限信息。 isEnabled()判断用户是否可用。 isAccountNonExpired()判断用户的账号是否过期。 isAccountNonLocked()判断用户的账号是否被锁定。 isCredentialsNonExpired()判断用户的凭证是否过期。 自定义用户信息时可以实现UserDetails接口并覆盖其中的方法来提供自己的用户信息。 6.2、业务对象UserDetailsService
修改UserServiceImpl并实现UserDetailsService重写loadUserByUsername(String username)方法。
Service
public class UserServiceImpl extends ServiceImplUserMapper, Userimplements UserService,UserDetailsService {
/*** 实现Spring Security内置的UserDetailService接口重写loadUserByUsername方法实现数据库的身份校验* param username* return* throws UsernameNotFoundException*/Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名查询数据库中用户信息User user this.getOne(new QueryWrapperUser().eq(username, username));//判断用户是否存在if(Objects.isNull(user))throw new UsernameNotFoundException(用户不存在);//权限校验TODO后续讲解return user;}
}
UserDetailsService是Spring Security中的一个接口它用于从特定数据源如数据库中获取用户详细信息以进行身份验证和授权。实现该接口的类需要实现loadUserByUsername方法该方法根据给定的用户名返回一个UserDetails对象该对象包含有关用户的详细信息例如密码、角色和权限等。在Spring Security中UserDetailsService通常与DaoAuthenticationProvider一起使用后者是一个身份验证提供程序用于验证用户的凭据。 6.3、SecurityConfig配置
创建WebSecurityConfig配置类配置SpringSecurity结合数据库方式进行身份认证和权限鉴定。
Configuration
EnableWebSecurity
public class WebSecurityConfig {
/*** 基于数据库方式进行身份认证和权限鉴定*/Autowiredprivate UserDetailsService userDetailsService;/*** 配置密码编码器首次采用明文密码方式进行比对校验*/Beanpublic PasswordEncoder passwordEncoder(){return NoOpPasswordEncoder.getInstance();}/*** 获取AuthenticationManager认证管理器登录时认证使用基于数据库方式* param* return* throws Exception*/Beanpublic AuthenticationManager authenticationManager() throws Exception {//创建DaoAuthenticationProviderDaoAuthenticationProvider providernew DaoAuthenticationProvider();//设置userDetailsService基于数据库方式进行身份认证provider.setUserDetailsService(userDetailsService);//配置密码编码器provider.setPasswordEncoder(passwordEncoder());return new ProviderManager(provider);}Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(/).permitAll().anyRequest().authenticated().and().formLogin().loginPage(/).loginProcessingUrl(/user/userLogin).passwordParameter(password).usernameParameter(username)// 认证成功 redirect跳转根据上一保存请求进行成功跳转.defaultSuccessUrl(/index)// 认证成功 forward跳转始终在认证成功之后跳转到指定请求
// .successForwardUrl(/index)
// .failureForwardUrl(/)/* .successHandler((request, response, exception)-{response.sendRedirect(/index);})*/.failureHandler((request, response, exception) - {request.setAttribute(msg,exception.getMessage());request.getRequestDispatcher(/).forward(request,response);}).and().logout().logoutUrl(/logout).logoutSuccessUrl(/).and().csrf().disable();return http.build();}
}
这里需要注意的是formLogin认证失败后将不在使用failureForwardUrl()方法转发而是使用failureHandler处理器方式处理错误信息并跳转页面。 如果使用failureForwardUrl()方式请到ForwardAuthenticationFailureHandler源码中查看错误信息封装 SpringSecurity将认证错误信息保存到Request作用域中并取名为SPRING_SECURITY_LAST_EXCEPTION所以直接可以到前端页面使用${SPRING_SECURITY_LAST_EXCEPTION}方式进行获取展示。 如果使用failureHandler处理器方式则可以自定义错误页面及错误信息
.failureHandler((request, response, exception) - {//将认证错误信息保存到request作用域取名为msgrequest.setAttribute(msg,exception.getMessage());//认证失败后转发到指定页面request.getRequestDispatcher(/).forward(request,response);
})
本次案例使用的是自定义failureHandler处理器方式修改登录页面login.ftl加入错误信息展示区域
div${msg!}/div 7、启动测试
在sys_user表中添加测试用户信息此处请使用明文密码方式进行身份验证。 修改IndexController中的跳转到首页的方法加入获取SpringSecurity认证信息并带入前段页面进行展示。
RequestMapping(/index)
public String toIndex(Model model){//获取Spring Security认证成功后的相关信息Authentication authentication SecurityContextHolder.getContext().getAuthentication();//将认证信息转换成JSON数据String json JSON.toJSONString(authentication);//存入数据模型中带入前端页面进行展示model.addAttribute(auth,json);return index;
} 启动项目并进行登录测试。 在index.ftl首页中通过${auth}展示SpringSecurity认证成功的相关信息。 三、密码方式 Spring Security提供了多种密码加密方式大致可以归类于以下几种 对密码进行明文处理即不采用任何加密方式 采用MD5加密方式 采用哈希算法加密方式 1、自定义MD5加密
创建自定义MD5加密类并实现PasswordEncoder
public class CustomMd5PasswordEncoder implements PasswordEncoder {Overridepublic String encode(CharSequence rawPassword) {//对密码进行 md5 加密String md5Password DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());System.out.println(md5Password);return md5Password;}Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {// 通过md5校验System.out.println(rawPassword);System.out.println(encodedPassword);return encode(rawPassword).equals(encodedPassword);}
} 修改SecurityConfig配置类更换密码编码器 Bean
public PasswordEncoder passwordEncoder(){// 自定义MD5加密方式return new CustomMd5PasswordEncoder();
} 数据库中的用户密码也需要更换成对应自定义MD5加密密码 //MD5自定义加密方式
String pwd DigestUtils.md5DigestAsHex(123456.getBytes());
System.out.println(pwd); 最后将生成的MD5加密密码保存到数据库表中。 2、BCryptPasswordEncoder密码编码器 BCryptPasswordEncoder是Spring Security中一种基于bcrypt算法的密码加密方式。bcrypt算法是一种密码哈希函数具有防止彩虹表攻击的优点因此安全性较高。 使用BCryptPasswordEncoder进行密码加密时可以指定一个随机生成的salt值将其与原始密码一起进行哈希计算。salt值可以增加密码的安全性因为即使两个用户使用相同的密码由于使用不同的salt值进行哈希计算得到的哈希值也是不同的。 在Spring Security中可以通过在SecurityConfig配置类中添加以下代码来使用BCryptPasswordEncoder进行密码加密 Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
} 这样就可以在Spring Security中使用BCryptPasswordEncoder进行密码加密了。 四、RememberMe 在实际开发中为了用户登录方便常常会启用记住我Remember-Me功能。如果用户登录时勾选了“记住我”选项那么在一段有效时间内会默认自动登录免去再次输入用户名、密码等登录操作。该功能的实现机理是根据用户登录信息生成 Token 并保存在用户浏览器的 Cookie 中当用户需要再次登录时自动实现校验并建立登录态的一种机制。 Spring Security提供了两种 Remember-Me 的实现方式 简单加密 Token用散列算法加密用户必要的登录系信息并生成 Token 令牌。 持久化 Token数据库等持久性数据存储机制用的持久化 Token 令牌。 基于持久化Token配置步骤如下 创建数据库表 persistent_logins用于存储自动登录信息
CREATE TABLE persistent_logins (username varchar(64) NOT NULL,series varchar(64) PRIMARY KEY,token varchar(64) NOT NULL,last_used timestamp NOT NULL
); 该步骤可以不做在后续的配置过程中可以交由SpringSecurity自动生成。 基于持久化Token配置修改SecurityConfig配置类
Remember-Me 功能的开启需要在configure(HttpSecurity http)方法中通过http.rememberMe()配置该配置主要会在过滤器链中添加 RememberMeAuthenticationFilter 过滤器通过该过滤器实现自动登录。
Configuration
EnableWebSecurity
public class WebSecurityConfig {
//省略其他配置参考之前Autowiredpublic UserDetailsService userDetailsService;Resourcepublic DataSource dataSource;/*** 配置持久化Token方式注意tokenRepository.setCreateTableOnStartup()配置*/Beanpublic PersistentTokenRepository persistentTokenRepository(){JdbcTokenRepositoryImpl tokenRepository new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// 设置为true要保障数据库该表不存在不然会报异常哦// 所以第二次打开服务器应用程序的时候得把它设为falsetokenRepository.setCreateTableOnStartup(false);return tokenRepository;}Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(/).permitAll().anyRequest().authenticated().and().formLogin().loginPage(/).loginProcessingUrl(/user/userLogin).passwordParameter(password).usernameParameter(username)// 认证成功 redirect跳转根据上一保存请求进行成功跳转.defaultSuccessUrl(/index)// 认证成功 forward跳转始终在认证成功之后跳转到指定请求//.successForwardUrl(/index)//failureForwardUrl(/)/*.successHandler((request, response, exception)-{response.sendRedirect(/index);})*/.failureHandler((request, response, exception) - {request.setAttribute(msg,exception.getMessage());request.getRequestDispatcher(/).forward(request,response);}).and().rememberMe()// 指定 rememberMe 的参数名用于在表单中携带 rememberMe 的值。//.rememberMeParameter(remember-me)// 指定 rememberMe 的有效期单位为秒默认2周。.tokenValiditySeconds(30)// 指定 rememberMe 的 cookie 名称。.rememberMeCookieName(remember-me-cookie)// 指定 rememberMe 的 token 存储方式可以使用默认的 PersistentTokenRepository 或自定义的实现。.tokenRepository(persistentTokenRepository())// 指定 rememberMe 的认证方式需要实现 UserDetailsService 接口并在其中查询用户信息。.userDetailsService(userDetailsService).and().logout().logoutUrl(/logout).logoutSuccessUrl(/).and().csrf().disable();return http.build();}
}
rememberMe主要方法介绍
方法说明rememberMeParameter()指定在登录时“记住我”的 HTTP 参数默认为 remember-metokenValiditySeconds()设置 Token 有效期为 200s默认时长为 2 星期tokenRepository()指定 rememberMe 的 token 存储方式可以使用默认的 PersistentTokenRepository 或自定义的实现userDetailsService()指定 UserDetailsService 对象rememberMeCookieName()指定 rememberMe 的 cookie 名称 修改登录页面login.ftl添加remember-Me记住我的checkbox选项框。
form action/user/userLogin methodpostlabel账号/labelinput typetext nameusername/br/label密码/labelinput typepassword namepassword/br/input typecheckbox nameremember-me/记住我br/input typesubmit value登 录/
/form 注意配置的checkbox复选框的name属性名要与上面配置的rememberMeParameter(属性名)一致默认就叫remember-me。 总结remember-me 只有在 JSESSIONID 失效和SecurityContextPersistenceFilter 过滤器认证失败或者未进行认证时才发挥作用。此时只要 remember-me 的 Cookie 不过期我们就不需要填写登录表单就能实现再次登录并且 remember-me 自动登录成功之后会生成新的 Token 替换旧的 Token相应 Cookie 的 Max-Age 也会重置。 五、CSRF防御
1、什么是CSRF CSRFCross-Site Request Forgery跨站请求伪造是一种利用用户已登录的身份在用户不知情的情况下发送恶意请求的攻击方式。攻击者可以通过构造恶意链接或者伪造表单提交等方式让用户在不知情的情况下执行某些操作例如修改密码、转账、发表评论等。 为了防范CSRF攻击常见的做法是在请求中添加一个CSRF Token也叫做同步令牌、防伪标志并在服务器端进行验证。CSRF Token是一个随机生成的字符串每次请求都会随着请求一起发送到服务器端服务器端会对这个Token进行验证如果Token不正确则拒绝执行请求。 2、SpringSecurity中如何使用CSRF 在Spring Security中防范CSRF攻击可以通过启用CSRF保护来实现。启用CSRF保护后Spring Security会自动在每个表单中添加一个隐藏的CSRF Token字段并在服务器端进行验证。如果Token验证失败则会抛出异常从而拒绝执行请求。启用CSRF保护的方式是在Spring Security配置文件中添加.csrf()方法例如 http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); 在上面的配置中我们使用了CookieCsrfTokenRepository作为CSRF Token的存储方式并设置了httpOnly为false以便在客户端可以访问到该Token。 .csrf()主要方法介绍
方法说明disable()关闭CSRF防御csrfTokenRepository()设置CookieCsrfTokenRepository实例用于存储和检索CSRF令牌。与HttpSessionCsrfTokenRepository不同CookieCsrfTokenRepository将CSRF令牌存储在cookie中而不是在会话中。ignoringAntMatchers()设置一组Ant模式用于忽略某些请求的CSRF保护。例如如果您想要忽略所有以/api/开头的请求可以使用.ignoringAntMatchers(/api/**)。csrfTokenManager()设置CsrfTokenManager实例用于管理CSRF令牌的生成和验证。默认情况下Spring Security使用DefaultCsrfTokenManager实例来生成和验证CSRF令牌。requireCsrfProtectionMatcher()设置RequestMatcher实例用于确定哪些请求需要进行CSRF保护。默认情况下Spring Security将对所有非GET、HEAD、OPTIONS和TRACE请求进行CSRF保护。
重启项目进行测试。 问题一开启了SpringSecurity的CSRF防御之后导致登录的POST请求失败
原因分析使用了 spring-security 后默认开启了防止跨域攻击的功能任何 POST 提交到后台的表单都要验证是否带有 _csrf 参数一旦传来的 _csrf 参数不正确服务器便返回 403 错误。
解决方案修改login.ftl页面代码加入_csrf隐藏域。
form action/user/userLogin methodpostinput typehidden name${_csrf.parameterName} value${_csrf.token}/label账号/labelinput typetext nameusername/br/label密码/labelinput typepassword namepassword/br/input typecheckbox nameremember-me/记住我br/input typesubmit value登 录/
/form
如果针对一些特定的请求接口不需要进行CSRF防御可以通过以下配置忽略
http.csrf().ignoringAntMatchers(/upload); // 禁用/upload接口的CSRF防御 问题二SpringSecurity退出登录/logout提示404问题
退出登录logout实现方式
http.logout().logoutUrl(/logout).logoutSuccessUrl(/).permitAll();
结果运行项目执行安全退出时提示页面404错误。
错误原因SpringSecurity3.2开始默认会启动CSRF防护一旦启动了CSRF防护“/logout” 需要用post的方式提交SpringSecurity才能过滤。 方式一配置文件直接关闭CSRF防护
http.csrf().disable(); //关闭csrf防护
注意当关闭CSRF防护时部分的页面可能会无法刷新甚至报错。这时可以在页面的header标签之间加入以下代码
meta name_csrf content${_csrf.token}/
meta name_csrf_header content${_csrf.headerName}/ 方式二官方建议使用POST请求退出登陆并携带CRSF令牌
http.logout().logoutRequestMatcher(new AntPathRequestMatcher(/logout)).logoutSuccessUrl(/).permitAll();分享就到这里欢迎大家评论区讨论