文章讲解了Spring Security的各个模块和功能。此中包罗用户认证、脚色授权、暗码加密和解密等。文章还提供了详细的代码示例,资助读者快速上手并明白Spring Security的使用。总之,本文是一篇全面而实用的Spring Security使用指南,对于想要学习和使用Spring Security的开辟者来说是一份非常有价值的资料。
一、入门使用
1,引入依靠
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
复制代码 2,访问请求
假设有如下的接口,当访问时会主动下载权限框架的登录页请求
3,自定义登录页
准备自定义的静态资源
添加设置
- @Configuration
- public class SecurityConfig {
- @Bean
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- // 配置表单登录
- http.formLogin()
- // 指定自定义的登录页面 URL
- .loginPage("/login.html")
- // 指定登录请求的处理 URL
- .loginProcessingUrl("/login")
- // 允许所有用户访问登录页面和登录处理 URL
- .permitAll()
- .and()
- // 配置授权请求
- .authorizeRequests()
- // 允许所有用户访问以下路径
- .antMatchers( "/css/**", "/js/**", "/images/**")
- .permitAll()
- // 对于其他所有请求,要求用户必须经过身份验证
- .anyRequest()
- .authenticated()
- .and()
- // 禁用 CSRF 保护
- .csrf()
- .disable();
- // 构建并返回安全过滤链
- return http.build();
- }
- }
复制代码 呈现结果
二、自定义认证
1,基于内存的认证
- @Bean
- PasswordEncoder passwordEncoder() {
- return NoOpPasswordEncoder.getInstance();
- }
- @Bean
- public UserDetailsService users() {
- UserDetails user = User.builder()
- .username("user")
- .password("123456")
- .roles("USER")
- .build();
- UserDetails admin = User.builder()
- .username("admin")
- .password("112233")
- .roles("USER", "ADMIN")
- .build();
- return new InMemoryUserDetailsManager(user, admin);
- }
复制代码 2,BCrypt暗码加密
BCrypt就是一款加密工具,可以比较方便地实现数据的加密工作。也可以简单明白为它内部自己实现了随机加盐处理。比方,使用MD5加密,每次加密后的密文其实都是一样的,这样就方便了MD5通过大数据的方式进行破解。BCrypt生成的密文长度是60,而MD5的长度是32。
- import org.springframework.security.crypto.bcrypt.BCrypt;
- public class Main {
- public static void main(String[] args) {
- byte[] bytes = "123456".getBytes();
- System.out.println(bytes);
- String hashpw = BCrypt.hashpw(bytes, BCrypt.gensalt());
- System.out.println("password-one:" + hashpw);
- String hash = BCrypt.hashpw(bytes, BCrypt.gensalt());
- System.out.println("password-two:" + hash);
- System.out.println("------------------------");
- System.out.println(BCrypt.checkpw(bytes, hash));
- System.out.println(BCrypt.checkpw(bytes, hashpw));
- System.out.println(BCrypt.checkpw("123456", hashpw));
- }
- }
复制代码
三、基于JDBC数据库实现认证
1,执行流程
2,基于内存代码执行
在Spring Security框架中提供了一个UserDetailsService 接口,它的主要作用是提供用户详细信息。详细来说,当用户尝试进行身份验证时,UserDetailsService 会被调用,以获取与用户相关的详细信息。这些详细信息包罗用户的用户名、暗码、脚色等
- import org.springframework.security.core.userdetails.User;
- 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 UserDetailsServiceImpl implements UserDetailsService {
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- if (username.equals("user")) {
- return User.builder()
- .username(username)
- .password("$2a$10$mPMldGTPYijVDItlA3/SsuAlv8OK2Rfz7VNbgdU4peyDCsxRqS95y")
- .roles("USER")
- .build();
- }
- if (username.equals("admin")) {
- return User.builder()
- .username(username)
- .password("$2a$10$mPMldGTPYijVDItlA3/SsuAlv8OK2Rfz7VNbgdU4peyDCsxRqS95y")
- .roles("USER", "ADMIN")
- .build();
- }
- return null;
- }
- }
复制代码 3,基于数据库代码执行
- @Component
- public class UserDetailsServiceImpl implements UserDetailsService {
- @Autowired
- private UserMapper userMapper;
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- // 根据用户名查询用户
- User user = userMapper.findByUsername(username);
- Assert.isTrue(user != null, "用户不存在");
- // 建立角色
- SimpleGrantedAuthority userRole = new SimpleGrantedAuthority("user");
- SimpleGrantedAuthority adminRole = new SimpleGrantedAuthority("admin");
- List<SimpleGrantedAuthority> roleList = new ArrayList<>();
- roleList.add(userRole);
- roleList.add(adminRole);
- return new org.springframework.security.core.userdetails.User(user.getUsername(),
- user.getPassword(), roleList);
- }
-
- }
复制代码 4,自定义框架的USER类
- import lombok.Data;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.SimpleGrantedAuthority;
- import org.springframework.security.core.userdetails.UserDetails;
- import java.util.Collection;
- import java.util.List;
- import java.util.stream.Collectors;
- @Data
- public class UserAuth implements UserDetails {
- private String username; //固定不可更改
- private String password;//固定不可更改
- private String nickName; //扩展属性 昵称
- private List<String> roles; //角色列表
- @Override
- public Collection<? extends GrantedAuthority> getAuthorities() {
- if (roles == null) return null;
- return roles.stream()
- .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
- .collect(Collectors.toList());
- }
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
- @Override
- public boolean isAccountNonLocked() {
- return true;
- }
- @Override
- public boolean isCredentialsNonExpired() {
- return true;
- }
- @Override
- public boolean isEnabled() {
- return true;
- }
- }
复制代码- @Component
- public class UserDetailsServiceImpl implements UserDetailsService {
- @Autowired
- private UserMapper userMapper;
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- // 根据用户名查询用户
- User user = userMapper.findByUsername(username);
- Assert.isTrue(user != null, "用户不存在");
- UserAuth userAuth = new UserAuth();
- BeanUtils.copyProperties(user, userAuth);
- // 建立角色
- List<String> roles=new ArrayList<>();
- if ("user@qq.com".equals(user.getUsername())) {
- roles.add("USER");
- }
- if ("admin@qq.com".equals(user.getUsername())) {
- roles.add("USER");
- roles.add("ADMIN");
- }
- userAuth.setRoles(roles);
- return userAuth;
- }
- }
复制代码 // 获取认证对象主体
UserAuth userAuth = (UserAuth) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
四、授权
1,简单WEB授权
新增两个接口
分配脚色
当使用user脚色访问/admin时,便会返回403权限不足
2,控制利用方法
● permitAll() 方法,所有用户可访问。
● denyAll() 方法,所有用户不可访问。
● authenticated() 方法,登录用户可访问。
● anonymous() 方法,匿名用户可访问。
● rememberMe() 方法,通过 remember me 登录的用户可访问。
● fullyAuthenticated() 方法,非 remember me 登录的用户可访问。
● hasIpAddress(String ipaddressExpression) 方法,来自指定 IP 表达式的用户可访问。
● hasRole(String role) 方法, 拥有指定脚色的用户可访问,传入的脚色将被主动增长 “ROLE_” 前缀。
● hasAnyRole(String... roles) 方法,拥有指定任意脚色的用户可访问。传入的脚色将被主动增长 “ROLE_” 前缀。
● hasAuthority(String authority) 方法,拥有指定权限( authority )的用户可访问。
● hasAnyAuthority(String... authorities) 方法,拥有指定任意权限( authority )的用户可访问。
5、整合JWT
1,实现流程
2,注册认证管理
- @Configuration
- public class SecurityConfig {
- @Bean
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- http.authorizeRequests().antMatchers("/security/login").permitAll();
- http.csrf().disable();
- return http.build();
- }
- @Bean
- public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
- return configuration.getAuthenticationManager();
- }
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- @Bean
- public UserDetailsService users() {
- UserDetails user = User.builder()
- .username("user")
- .password("$2a$10$2VCyByZ5oeiXCEN73wvBB.xpmJgPBbZVS/Aallmdyij2G7hmAKQTG")
- .roles("USER")
- .build();
- UserDetails admin = User.builder()
- .username("admin")
- .password("$2a$10$cRH8iMMh6XO0T.ssZ/8qVOo8ThWs/qfntIH3a7yfpbPd05h9ZGx8y")
- .roles("USER", "ADMIN")
- .build();
- return new InMemoryUserDetailsManager(user, admin);
- }
- }
复制代码 3,登录接口
- @PostMapping("/login")
- public String login(@RequestBody LoginDto loginDto){
- // 使用接收到的用户名和密码创建一个认证令牌对象。
- UsernamePasswordAuthenticationToken authenticationToken =
- new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
- // 调用Spring Security的认证管理器来验证提供的认证令牌。
- // 如果用户名或密码不正确,这一步会抛出异常。
- Authentication authenticate = authenticationManager.authenticate(authenticationToken);
- if (authenticate.isAuthenticated()) {
- // 获取认证成功的主体
- Object principal = authenticate.getPrincipal();
- Map<String, Object> claims = new HashMap<>();
- claims.put("user", principal);
- String token = JWTUtil.createToken(claims, JWT_KEY.getBytes());
- log.info("token: {}", token);
- return token;
- }
- return "";
- }
复制代码 4,自定义认证管理
- @Component
- public class TokenAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
- @Override
- public AuthorizationDecision check(Supplier<Authentication> authentication,
- RequestAuthorizationContext requestAuthorizationContext) {
- HttpServletRequest request = requestAuthorizationContext.getRequest();
- String token = request.getHeader("token");
- if (!StringUtils.hasText(token)) {
- return new AuthorizationDecision(false);
- }
- Claims claims = JwtUtil.parseJWT(JWT_KEY, token);
- //获取userAuth
- UserAuth user = JSONObject.parseObject(JSON.toJSONString(claims.get("user")),UserAuth.class);
- //存入上下文
- UsernamePasswordAuthenticationToken auth
- =new UsernamePasswordAuthenticationToken( userAuth, userAuth.getPassword(), userAuth.getAuthorities());
- SecurityContextHolder.getContext().setAuthentication(auth);
- if (user != null) {
- return new AuthorizationDecision(false);
- }
- String requestURI = request.getRequestURI();
- if (user.getRoles().contains("admin")) {
- if("/hello/admin".equals(requestURI)){
- return new AuthorizationDecision(true);
- }
- }
- if(user.getRoles().contains("USER")){
- if("/hello/user".equals(requestURI)){
- return new AuthorizationDecision(true);
- }
- }
- return new AuthorizationDecision(false);
- }
- }
复制代码- @Autowired
- private TokenAuthorizationManager tokenAuthorizationManager;
- @Bean
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- http.authorizeHttpRequests().antMatchers("/security/login").permitAll()
- .anyRequest().access(tokenAuthorizationManager);
- http.csrf().disable();
- //关闭session
- http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
- //关闭缓存
- http.headers().cacheControl().disable();
- return http.build();
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |