Spring Security框架入门使用

关于Spring Security框架的依赖的参考代码为

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

1.使用自定义的用户名与密码

  1. UserDetailsServiceImpl 类,在类的声明之前添加 @Component 注解,实现UserDetailsService 接口,重写接口中的抽象方法
@Component
public class UserDetailsServiceImpl implements UserDetailsService { 
@Override 
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserDetails userDetails = User.builder() .username("root") .password("1234") .authorities("稍后再解释……") .build(); 
return userDetails; } }

在 UserDetailsService 接口中的 loadUserByUsername() 方法是由Spring Security框架调用的,当用户在登录页面中输入用户名、密码之后,Spring Security就会使用用户提交的用户名来调用 loadUserByUsername() 方法,该方法应该返回与用户名匹配的用户信息,例如用户的密码等等,Spring Security会自动完成接下来的密码对比及授权等过程。

  1. 然后,在 cn.tedu.straw.portal.security 包下创建 WebSecurityConfigurer 类,在类的声明之前添加 @Configuration 解,继承自WebSecurityConfigurerAdapter 类,主要重写其中的 void config(AuthenticationManagerBuilder auth) 方法:
@Configuration 
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { 
@Autowired 
UserDetailsServiceImpl userDetailsService; 
@Bean 
public PasswordEncoder passwordEncoder() { // 配置密码加密器 // Spring Security会自动将用户提交的密码使用这个密码加密器进行加密再对 比 
return NoOpPasswordEncoder.getInstance(); 
}

@Override 
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
// 配置身份验证 
auth.userDetailsService(userDetailsService); 
} }

登录流程

  1. 当用户在登录页面输入用户名、密码后,Spring Security将获取到这2个值;
  2. 由于自定义了 WebSecurityConfigurer 类,并配置了
    auth.userDetailsService(userDetailsService); ,则Spring Security会使用用
    户提交的用户名来调用 UserDetailsServiceImpl 中 loadUserByUsername() 方
    法,并得到 UserDetails 类型的结果;
  3. Spring Security会自动装配一个 PasswordEncoder 对象,并调用其方法对用户提交
    的密码进行加密,与 UserDetails 对象中的密码进行对比验证。

3.密码加密器

Spring Security允许在密文的密码值之前添加算法ID,则不需要指定密码加密器,Spring Security也会根据算法ID自动使用相应的算法来验证密码!

private static PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    public static String encode(String password){
        return "{bcrypt}" + passwordEncoder.encode(password);
    }

4.关于授权访问

,可以在自定义的 WebSecurityConfigurer 类中重写 void configure(HttpSecurity http) 方法来配置:

 http.authorizeRequests()
                .antMatchers(urls).permitAll()
                .anyRequest().authenticated();

// authorizeRequests() > 对请求进行授权
// antMatchers() > 设置某一些路径
// hasAuthority() > 需要具有某权限标识才可以访问,需在此前搭配 antMatchers()或其它用于设置路径的方法一起使用
// anyRequest() > 任意请求路径,如果此前通过其它API配置了路径,则表示“除了 以上路径以外的其它任意请求路径”
// authenticated() > 要求授权

Spring Security要求得到一个 UserDetails 类型的对象,然后自动完成身份验证和授权访问,但是, UserDetails 类型中可以封装的属性并不足以满足实际编程需求,例如连用户的ID和昵
称都无法封装进行,不便于后续的操作中识别用户的身份、获取常用信息,为了解决这个问题,应该自定义类,在原有的 UserDetails 实现类的基础之上进行扩展!在 cn.tedu.straw.portal.security 包下创建 LoginUserInfo 类,继承自Spring Security中 的 User 类(即 UserDetails 接口的实现类):

@Setter @Getter @ToString public class LoginUserInfo extends User { private Integer userId; private String nickName; public LoginUserInfo(String username, String password, Collection<? extends GrantedAuthority> authorities) { super(username, password, authorities); }public LoginUserInfo(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); } }

然后,修改 UserDetailsServiceImpl 类,通过用户名查询用户详情,并封装为以上定义的LoginUserInfo 类型返回给Spring Security框架

@Component public class UserDetailsServiceImpl implements UserDetailsService { @Autowired IUserService userService; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { // 调用业务层根据登录时填写的手机号查询数据库中的数据 UserLoginVO userLoginVO = userService.loginByPhone(s); // 如果手机号没有对应的数据,则直接返回null,登录将失败 if (userLoginVO == null) { return null; }// 从查询结果中取出权限数据,封装为Spring Security需要的类型 List<GrantedAuthority> authorities = new ArrayList<>(); List<PermissionVO> permissions = userLoginVO.getPermissions(); for (PermissionVO permission : permissions) {
String authority = permission.getAuthority(); GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority); authorities.add(grantedAuthority); }// 创建LoginUserInfo对象,准备作为返回给Spring Security的对象 LoginUserInfo loginUserInfo = new LoginUserInfo( userLoginVO.getPhone(), userLoginVO.getPassword(), userLoginVO.getIsEnabled() == 1, true, true, userLoginVO.getIsLocked() == 0, authorities );loginUserInfo.setUserId(userLoginVO.getId()); loginUserInfo.setNickName(userLoginVO.getNickName()); // 返回 return loginUserInfo; } }

然后,在 WebSecurityConfigurer 中已经配置了使用以上 UserDetailsServiceImpl 的对象:

@Configuration public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Autowired UserDetailsServiceImpl userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置身份验证 auth.userDetailsService(userDetailsService); }@Override protected void configure(HttpSecurity http) throws Exception { // 访问控制 // authorizeRequests():对请求进行验证 // antMatchers():设置请求路径 // permitAll():直接许可,即不需要验证 // anyRequest():除了此前配置过的URL以外的所有请求 // authenticated():必须已经验证 // formLogin():通过登录表单来验证用户登录 // csrf():跨域攻击 // disable():禁止 // 登录页面的URL String loginUrl = "/login.html"; // 处理登录表单的URL String loginProcessingUrl = "/login"; // 不需要登录即可请求的URL(白名单) String[] urls = { loginUrl, loginProcessingUrl, "/register.html"};http.authorizeRequests() .antMatchers(urls).permitAll() .anyRequest().authenticated(); http.formLogin() .loginPage(loginUrl) .loginProcessingUrl(loginProcessingUrl); http.csrf().disable(); } }

使用自定义页面

登录表单必须提交到 /login 位置;
用于输入用户名和密码的输入框的 name 必须是 username 和 password 。

全局获取用户登录信息


```bash
public R<Void> post(@Valid PostQuestionDTO postQuestionDTO, BindingResult bindingResult,
@AuthenticationPrincipal LoginUserInfo loginUserInfo){
if(bindingResult.hasErrors()){
            String message = bindingResult.getFieldError().getDefaultMessage();
            throw new InvalidParameterException(message);
        }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值