安全框架
安全框架,简单说是对访问权限进行控制,应用的安全性包括用户认证(Authentication)
和用户授权(Authorization)
两个部分。
- 用户认证:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程。
- 用户授权:验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。
一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
Apache Shiro
Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro 要简单的多。
Spring Security
Spring Security 是一个强大的可高度定制的认证和授权框架,对于 Spring 应用来说它是一套 Web 安全标准。Spring Security 注重于为 Java 应用提供认证和授权功能,像所有的Spring项目一样,它对自定义需求具有强大的扩展性。
小结
Apache Shiro 因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。合适的才是最好的!
Spring Boot 整合 Spring Security
1.添加依赖
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.启动项目
启动日志增加了如下内容,通过该内容可以找到默认
用户名
和密码
- 用户名:UserDetailsServiceAutoConfiguration 类 -> User 类 -> private String name = “user”;
- 密码:5b7773d7-1c0c-432f-9363-de1bd8fe6166
2022-04-22 14:15:46.762 WARN 8284 --- [ main] .s.s.UserDetailsServiceAutoConfiguration :
Using generated security password: 5b7773d7-1c0c-432f-9363-de1bd8fe6166
This generated password is for development use only. Your security configuration must be updated before running your application in production.
3.登录
访问:http://127.0.0.1:8080/user/1 接口,跳转到:http://127.0.0.1:8080/login 登录页面(security 默认登录页面),输入用户名、密码即可跳转回接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhF0abLG-1650617709540)(O:\appCache\Typora\img\【安全篇】Spring Boot 整合 Spring Security 安全框架\image-20220422142048281.png)]
登录后的用户信息默认在
Cookies
Name | Value |
---|---|
JSESSIONID | A58341FC3E4BD7A71700C4F65FF26AF3 |
Spring Security 定制化登录
模拟从数据库读取用户名密码,Demo 地址:mingyue-springboot-security
1.自定义登录认证逻辑
-
MingYueUserDetailsService
用户登录的逻辑处理处
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.csp.mingyue.security.model.MingYueUser; import com.csp.mingyue.security.vo.LoginUserVo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; 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; /** * @author Strive * @date 2022/4/22 14:53 * @description */ @Slf4j @Component @RequiredArgsConstructor public class MingYueUserDetailsService implements UserDetailsService { private final MingYueUserService mingYueUserService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { if (StrUtil.isBlank(username)) { log.info("登录用户:{} 不存在", username); throw new UsernameNotFoundException("登录用户:" + username + " 不存在"); } // 查出密码 MingYueUser user = mingYueUserService.queryUserByName(username); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在", username); throw new UsernameNotFoundException("登录用户:" + username + " 不存在"); } return new LoginUserVo(user); } }
-
MingYueUser
import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; /** @author Strive */ @Data @ToString @Builder @NoArgsConstructor @AllArgsConstructor public class MingYueUser { private Long userId; private String username; private String password; }
-
LoginUserVo
import com.csp.mingyue.security.model.MingYueUser; import java.util.Collection; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import org.springframework.security.core.CredentialsContainer; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; /** * 登录用户信息 * * @author Strive * @date 2022/4/22 14:59 * @description */ @Data @ToString @NoArgsConstructor @AllArgsConstructor public class LoginUserVo implements UserDetails, CredentialsContainer { /** 用户 */ private MingYueUser mingYueUser; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return new BCryptPasswordEncoder().encode(mingYueUser.getPassword()); } @Override public String getUsername() { return mingYueUser.getUsername(); } /** 账户是否未过期,过期无法验证 */ @Override public boolean isAccountNonExpired() { // true:未过期 return true; } /** * 指定用户是否解锁,锁定的用户无法进行身份验证 * * <p>密码锁定 */ @Override public boolean isAccountNonLocked() { // true:未锁定 return true; } /** 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 */ @Override public boolean isCredentialsNonExpired() { // true:未过期 return true; } /** 用户是否被启用或禁用。禁用的用户无法进行身份验证。 */ @Override public boolean isEnabled() { // true:未禁用 return true; } /** 认证完成后,擦除密码 */ @Override public void eraseCredentials() { mingYueUser.setPassword(null); } }
-
MingYueUserService
import com.csp.mingyue.security.model.MingYueUser; import org.springframework.stereotype.Service; /** @author Strive */ @Service public class MingYueUserService { /** * 根据用户名查询用户信息 * * @param username 用户名 * @return 用户信息 */ public MingYueUser queryUserByName(String username) { return MingYueUser.builder().userId(1L).username(username).password("123456").build(); } }
2.登录成功的处理
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
/**
* @author Strive
* @date 2022/4/22 15:07
* @description
*/
@Slf4j
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(
HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException, ServletException {
log.info("login error");
if (e instanceof AccountExpiredException) {
// 账号过期
log.info("[登录失败] - 用户账号过期");
} else if (e instanceof BadCredentialsException) {
// 密码错误
log.info("[登录失败] - 用户密码错误");
} else if (e instanceof CredentialsExpiredException) {
// 密码过期
log.info("[登录失败] - 用户密码过期");
} else if (e instanceof DisabledException) {
// 用户被禁用
log.info("[登录失败] - 用户被禁用");
} else if (e instanceof LockedException) {
// 用户被锁定
log.info("[登录失败] - 用户被锁定");
} else {
// 其他错误
log.error(String.format("[登录失败] - [%s]其他错误"), e);
}
}
}
3.登录失败的处理
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
/**
* @author Strive
* @date 2022/4/22 15:05
* @description
*/
@Slf4j
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
log.info("login success");
}
}
4.配置 Spring Security
import com.csp.mingyue.security.handler.LoginFailureHandler;
import com.csp.mingyue.security.handler.LoginSuccessHandler;
import com.csp.mingyue.security.service.MingYueUserDetailsService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
/**
* Spring Security 配置
*
* @author Strive
* @date 2022/4/22 15:11
* @description
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final MingYueUserDetailsService mingYueUserDetailsService;
/** 登录成功的处理 */
private final LoginSuccessHandler loginSuccessHandler;
/** 登录失败的处理 */
private final LoginFailureHandler loginFailureHandler;
/** 配置认证方式等 */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(mingYueUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
/** http相关的配置,包括登入登出、异常处理、会话管理等 */
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests()
// 放行接口
// .antMatchers().permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest()
.authenticated()
// 登入
.and()
.formLogin()
// 允许所有用户
.permitAll()
// 登录成功处理逻辑
.successHandler(loginSuccessHandler)
// 登录失败处理逻辑
.failureHandler(loginFailureHandler);
}
}
5.登录测试
地址 | 用户名 | 密码 |
---|---|---|
http://127.0.0.1:8080/login | mingyue | 123456 |
补充说明
Spring Security 中文文档:
- https://www.docs4dev.com/docs/zh/spring-security/5.1.2.RELEASE/reference/
- https://docs.gitcode.net/spring/guide/spring-security/overview.html#%E5%BC%80%E5%A7%8B
接口类 | 说明 |
---|---|
AuthenticationEntryPoint | 实现 AuthenticationEntryPoint 接口,可以处理匿名用户访问无权限资源时的异常 |
UserDetailsService | 用户登录认证逻辑 |
AuthenticationSuccessHandler | 登录成功的处理 |
AuthenticationFailureHandler | 登录失败的处理 |
LogoutSuccessHandler | 退出登录的回调 |
InvalidSessionStrategy | 登录超时的处理 |
SessionInformationExpiredStrategy | 同一账号同时登录的用户数受限的处理 |
AccessDeniedHandler | 登录用户没有权限访问的处理 |
HttpSessionIdResolver | 自定义 Session 解析器 |
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/78331.html