1.springsecurity底层实现为一条过滤器链。其实就是认证和授权

2.springsecurity自带一个登录页。对登录请求入手,替换掉自带的,对输入的账号密码进行验证。

3.定义一个配置类 继承 WebSecurityConfigurerAdapter

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/*
	 * 配置策略
	 *
	 * @param httpSecurity
	 * 
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {
		httpSecurity
				// 由于使用的是JWT,我们这里不需要csrf
				.csrf().disable()
				// 基于token,所以不需要session
		.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
				// 过滤请求
				.authorizeRequests()
				// 对于登录login 图标 静态资源允许匿名访问
				.antMatchers("/login/**").anonymous()
				.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()  //访问此地址不需要身份认证
				// 对于以上 没有添加的 都需经过过滤器认证
				// 除上面外的所有请求全部需要鉴权认证
				.anyRequest().authenticated().and().headers().frameOptions().disable();
		
	}
}

4.自定义一个对象实现UserDetails(Security提供),接下来的认证过程需要用到

import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;

@Setter
@Getter
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SecurityUser implements UserDetails{
	

    private Integer userId;
    
    private String username;
    
    private String password;
    
    //用户权限
    private Collection<? extends GrantedAuthority> authorities;
    
	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return username;
	}

    /**
     * 返回分配给用户的角色列表
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    /**
     * 账户是否未过期,过期无法验证
     * @return
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 指定用户是否解锁,锁定的用户无法进行身份验证
     * @return
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
     * @return
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 是否可用 ,禁用的用户不能身份验证
     * @return
     */
    @Override
    public boolean isEnabled() {
        return true;
    }
 
}

5.定义账号密码登录业务 实现UserDetailsService接口,这里的SysUserService根据自己的用户实体类

@Slf4j
@Service("userDetailsService")
public class UserDetailServiceImpl implements UserDetailsService {

	@Autowired
	private SysUserService sysUserService;

	/**
	 * 
	 * @Description: 账号密码登录业务
	 * @author: zhou
	 * @date: 2022年6月29日 下午4:39:10
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //根据登录用户名 从数据库中查询登录用户信息
		SysUser user = sysUserService.loginByUserName(username);
		if (user == null) {
			log.info("登录用户:" + username + " 不存在.");
			throw new RuntimeException("登录用户:" + username + " 不存在");
		}
		List<String> list = new ArrayList<String>(Arrays.asList("admin","test"));
		List<SimpleGrantedAuthority> authorities = list.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
	
		return new SecurityUser(user.getUserId(),username,user.getPassword(), authorities);
	}


}

5.1 注意:返回用户权限一定不能为空或者null

5.2 这里获取到用户密码  是经过加密后的密码(数据库存的密码是加密后的),下面也会讲到

6.定义自己登录业务  的实现类

	/**
	 * @Description: TODO(这里用一句话描述这个类的作用)
	 * @param:
	 * @return:
	 * @author: zhou
	 * @date: 2022年6月29日 下午8:33:54
	 */
	@Override
	public String login(String username, String password) {

		// 用户验证
		Authentication authentication = authenticationManager
				.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        //其实 就是执行 上面UserDetailServiceImpl的方法

		if (authentication == null) {
			throw new RuntimeException("登录失败");
		}
		// 存储认证信息
		SecurityContextHolder.getContext().setAuthentication(authentication);
		// 生成token
		SecurityUser userDetail = (SecurityUser) authentication.getPrincipal();

		return JWTUtils.generateToken(userDetail); //这个根据自己定义吧
	}

7.在配置类中添加上自己的登录业务。让springSecurity 根据加密规则对原生登录进行加密再与数据库中密码比对。

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailServiceImpl userDetailsService;

	@Override
	public void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
	}


}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐