Spring Security 实现自定义登录和认证(1):使用自定义的用户进行认证

1 SpringSecurity

1.1 导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

1.2 编写配置类

在spring最新版中禁用了WebSecurityConfigurerAdapter类,官方推荐采用配置类的方法进行配置。

  • 新建一个配置类,注意添加注释@EnableWebSecurity
    在这里插入图片描述

1.3 示例

  • 在类中添加一个Bean,生成过滤方法

      @Bean
      public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
          http
                  .authorizeHttpRequests((authz) -> authz
                          .anyRequest().authenticated()
                  )
                  .httpBasic(withDefaults());
          return http.build();
      }
    

    在这里插入图片描述

  • 忽略某个路径下的请求

      @Bean
      public WebSecurityCustomizer webSecurityCustomizer() {
          return (web) -> web.ignoring().requestMatchers("/level2", "/level3");
      }
    

    效果就是当我请求http://localhost:8080/level2的时候,就会重复跳出登录页面

1.4 自定义User实现登录

1.4.1 编写User类

在这里插入图片描述

1.4.2 定义UserRepository接口,用来实现从数据库或其它地方查询User

在这里插入图片描述

1.4.3 自定义一个类实现UserDetails接口

该类实现了UserDetails接口,这个UserDetails接口就是来查找用户名什么的。下面创建一个类,它继承了自定义的MyUser类且实现了UserDetails接口。(为什么要继承MyUser类?因为官方示例这么做的。。。)

在这里插入图片描述

package com.wjj.security.domain;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class MyUserDetails extends MyUser implements UserDetails {
    
    //定义构造函数
    public MyUserDetails(MyUser myUser){
        super(myUser.getId(), myUser.getUsername(), myUser.getPassword());
    }


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getUsername() {
        return super.getUsername();//把这里改成父类返回的username
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;//改成true
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}
1.4.4 定义一个类实现UserDetailsService接口

这个类是用来检索用户名和密码的,该类被DaoAuthenticationProvider调用,至于DaoAuthenticationProvider是什么可以查看官方文档。

在这里插入图片描述

package com.wjj.security.service;

import com.wjj.security.domain.MyUser;
import com.wjj.security.domain.UserRepository;
import jakarta.annotation.Resource;
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.Service;

@Service
public class CustomUserDetailService implements UserDetailsService {

    //注入编写的UserRepository
    @Resource
    private UserRepository userRepository;


    //根据username查询user
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        MyUser user = userRepository.findUserByUsername(username);
        if(user == null){
            throw  new UsernameNotFoundException(username + " Not found");
        }
        //要返回一个UserDetails
        //这个东西就是前面实现的那个类
        //用来验证该user是否有效
        return new MyUserDetails(user);
    }
}

可以看到本节的功能就是根据username寻找User,然后返回一个UserDetails。我甚至可以在上面的函数中直接从数据库或内存中查询User,而这行代码的功能正是如此:

在这里插入图片描述



1.4.5 实现UserRepository接口进行查找用户

在前面的代码中,loadUserByUsername 中的这行代码还没有实现其中的查询逻辑,接下来进行实现。

在这里插入图片描述
编写一个类实现findUserByUsername接口

在这里插入图片描述

在数据库进行User的查找就可以在这一步中实现了

package com.wjj.security.domain;

import java.util.Map;

public class MyUserRepository implements UserRepository{
    private Map<String, MyUser> usernameToUser;

    public MyUserRepository(Map<String, MyUser> usernameToUser){
        this.usernameToUser = usernameToUser;
    }

    
    @Override
    public MyUser findUserByUsername(String username) {
        return usernameToUser.get(username);
    }
}

然后将这个MyUser变成Spring的一个Resource,因为我们前面在CustomUserDetailService中引用UserRepository时用到了@Resource注释:

在这里插入图片描述

1.4.6 创建内存用户

在Application中new一个MyUserRepository实例,作为一个内存中存在的用户,并把它交给Spring托管:

package com.wjj.security;

import com.wjj.security.domain.MyUser;
import com.wjj.security.domain.MyUserRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
public class SecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }

    @Bean
    MyUserRepository myUserRepository(){
        MyUser user = new MyUser(1L, "username", "{bcrypt}$2a$10$h/AJueu7Xt9yh3qYuAXtk.WZJ544Uc2kdOKlHu2qQzCh/A3rq46qm");
        Map<String, MyUser> myUserMap = new HashMap<>();
        myUserMap.put("username", user);
        return new MyUserRepository(myUserMap);
    }

}

代码中的那堆字母时经过加密的密码,在前端用户输入密码之后传到后端时进行了加密。


1.4.7 启动项目进行登录

在这里插入图片描述
登陆成功:

在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
使用 Spring Security 实现自定义接口认证一般需要以下步骤: 1. 创建一个实现了 `UserDetailsService` 接口的类,用于从数据库中获取用户信息。 2. 实现一个 `PasswordEncoder` 接口的类,用于对用户密码进行加密和解密。 3. 配置 `WebSecurityConfigurerAdapter` 类,用于配置 Spring Security 的相关设置,如登录页面、登录成功后的跳转页面等。 4. 在 `WebSecurityConfigurerAdapter` 中使用 `AuthenticationManagerBuilder` 配置认证管理器,将自定义的 `UserDetailsService` 和 `PasswordEncoder` 注入其中,以实现用户信息的认证和密码加密解密。 5. 在控制器中使用 `@PreAuthorize` 注解对需要认证的接口进行权限控制。 下面是一个简单的示例代码: ```java @Service public class UserService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), AuthorityUtils.createAuthorityList(user.getRoles())); } } @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Autowired private PasswordEncoder passwordEncoder; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/api/**").authenticated().and().formLogin(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(passwordEncoder); } } @RestController @RequestMapping("/api") public class ApiController { @GetMapping("/hello") @PreAuthorize("hasRole('USER')") public String hello() { return "Hello, world!"; } } ``` 在上面的示例代码中,`UserService` 实现了 `UserDetailsService` 接口,并通过注入 `UserRepository` 实现了从数据库中获取用户信息的功能。`WebSecurityConfig` 继承了 `WebSecurityConfigurerAdapter`,并使用 `AuthenticationManagerBuilder` 配置了认证管理器,将自定义的 `UserDetailsService` 和 `PasswordEncoder` 注入其中。 在 `ApiController` 中,使用了 `@PreAuthorize` 注解对需要认证的 `/api/hello` 接口进行了权限控制,只有拥有 `USER` 角色的用户才能访问该接口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值