【Spring Security + OAuth2 + JWT入门到实战】3. 自定义用户认证逻辑

感情迁移 提交于 2020-03-01 18:55:32

简介

上一步已经完成登录,使用security默认提供的用户名和密码登录,这一章我们实现自定义用户名和密码登录。

处理用户信息获取逻辑

security默认处理用户信息获取逻辑,要想实现自己的逻辑那就要新建自己的逻辑类然后去实现security默认逻辑

org.springframework.security.core.userdetails.UserDetailsService

在browser项目新建MyUserDetailsService类去实现UserDetailsService重写loadUserByUsername方法

package com.spring.security;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return null;
    }
}

我们先打开返回值UserDatails源码看看里面有什么方法

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.core.userdetails;

import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}
  • getAuthorities()    #权限信息
  • getPassword()   #密码
  • getUsername()  #用户名
  • isAccountNonExpired()  #你的账户是否过期  返回true没有过期  返回false已过期
  • isAccountNonLocked()  #你的账号是否锁定  返回true没有被锁定  返回false已经被锁定   用户可以申请恢复
  • isCredentialsNonExpired()  #你的密码是否过期  返回true没有过期  返回false已过期
  • isEnabled()  #你的账号是否被删除 返回true未删除  返回false已删除 一般数据库伪删除不能用户不能申请恢复

 

修改loadUserByUsername方法去定义自己的用户名和密码:

security提供的两种User构造方法:

返回:用户名,密码,用户权限资料。账号是否被删除,账户是否过期,密码是否过期,账号是否锁定默认都是true

public User(String username, String password, Collection<? extends GrantedAuthority> authorities)

 

返回:用户名,密码,账号是否被删除,账户是否过期,密码是否过期,账号是否锁定,用户权限资料

public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities)

直接测试下面这个返回值的方法:

package com.spring.security;

import org.springframework.security.core.authority.AuthorityUtils;
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 MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("登录用户名:" + username);
        //这里可以通过用户名去数据库查用户的密码和账号状态,权限。
        //先写死
        return new User(username,"123456",true,true,true,false, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

启动项目测试,不管密码是否正确都会提示账号已被锁定。

修改accountNonLocked为true再重启项目:

启动以后输入用户名和密码点登陆发现报异常,这个异常是spring security5+后密码策略变更了。必须使用 PasswordEncoder 方式也就是你存储密码的时候 
需要使用{noop}123456这样的方式,这个在官网文档中有讲到。由于我们没有使用加密策略等等我们解决这个问题。

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

修改passaword值为{noop}123456,再启动项目:

错误密码:

正确密码:

处理密码加密解密

创建BrowserSecurityConfig类去继承WebSecurityConfigurerAdapter类

package com.spring.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

在UserDetailsService中我们模拟存入数据库中的密码就是加密后的字符串

package com.spring.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("登录用户名:" + username);
        //这里可以通过用户名去数据库查用户的密码和账号状态,权限。
        //这一步应该是放在注册那一步然后从数据库取密码,这里我们是模拟加密
        String password = passwordEncoder.encode("123456");
        return new User(username, password, true, true, true, true, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

框架会把提交的密码使用我们定义的passwordEncode加密后调用

org.springframework.security.crypto.password.PasswordEncoder#matches方法,与返回的User中的密码进行比对。配对正常就验证通过;

启动项目测试:

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!