springsecurity认证流程:loaduserbyusername()方法内部实现。
实现步骤
构建一个自定义的service接口,实现springsecurity的userdetailservice接口。
建一个service实现类,实现此loaduserbyusername方法。
调用登录的login接口,会经过authenticationmanager.authenticate(authenticationtoken)方法。此方法会调用loaduserbyusername方法。
方法内部做用户信息的查询,判断用户名和密码是否正确,这是第一道认证。
@service
@requiredargsconstructor
public class userdetailsserviceimpl implements userdetailsservice {
private final sysusermapper sysusermapper;
//用户登录请求/login,自动调用方法
//根据用户名获取用户信息
//userdetails 存储用户信息,包括用户名,密码,权限
@override
public userdetails loaduserbyusername(string username) throws usernamenotfoundexception {
lambdaquerywrapper<sysuser> wrapper = new lambdaquerywrapper<>();
wrapper.eq(sysuser::getusername, username);
sysuser sysuser = sysusermapper.selectone(wrapper);
if (objects.isnull(sysuser)){
throw new usernamenotfoundexception("用户名不存在");
}
//认证成功回userdetails对象
return new loginuser(sysuser);
}
}
@tostring
public class loginuser implements userdetails {
private sysuser sysuser;
public loginuser(sysuser sysuser) {
this.sysuser = sysuser;
}
// 权限
@override
public collection<? extends grantedauthority> getauthorities() {
return list.of();
}
@override
public string getpassword() {
return sysuser.getpassword();
}
@override
public string getusername() {
return sysuser.getusername();
}
// 账号是否过期
@override
public boolean isaccountnonexpired() {
return true;
}
// 账号是否被锁定
@override
public boolean isaccountnonlocked() {
return true;
}
// 密码是否过期
@override
public boolean iscredentialsnonexpired() {
return true;
}
// 账号是否可用
@override
public boolean isenabled() {
return true;
}
}如果没有查到信息就抛出异常。
如果查到信息了再接着查用户的权限信息,返回权限信息到loginuser实体。
此实体实现了springsecurity自带的userdetail接口。实现了getauthorities方法。
每次查询权限都会调用此方法。
查询到的权限,会被返回到login接口。进行后续操作。
如果认证通过,通过身份信息中的userid生产一个jwt。
把完整的用户信息作为value,token作为key存入redis。
@restcontroller
@tag(name = "认证模块", description = "认证模块")
@requestmapping("/auth")
@requiredargsconstructor
public class authcontroller {
//注入authenticationmanager(认证管理器)
private final authenticationmanager authenticationmanager;
private final jwtutils jwtutils;
@postmapping("/login")
@operation(summary = "登录")
public result login(@requestparam("username") string username, @requestparam("password") string password) {
system.out.println(username + password);
//登录逻辑
//调用userdetailsservice.loaduserbyusername方法获取
//不能直接调用,需要通过authenticationmanager进行认证
authentication authentication = new usernamepasswordauthenticationtoken(username, password);
authentication authenticate = null;
try {
authenticate = authenticationmanager.authenticate(authentication);
} catch (badcredentialsexception e) {
return result.failed(resultcode.username_or_password_error);
}
//认证成功方法token
string token=jwtutils.generatetoken(authenticate);
return result.success(token);
}
}
@configuration
@enablewebsecurity // 开启web安全
@enablemethodsecurity
@requiredargsconstructor
public class securityconfig {
private final ignoredurl ignoredurl;
/**
* 配置认证管理器 authenticationmanager
* 作用:用于身份认证
* 参数:userdetailsservice, passwordencoder
*/
@bean
public authenticationmanager authenticationmanager(userdetailsservice userdetailsservice, passwordencoder passwordencoder) {
daoauthenticationprovider provider = new daoauthenticationprovider();
provider.setuserdetailsservice(userdetailsservice);
provider.setpasswordencoder(passwordencoder);
return new providermanager(provider);
}
/**
* 密码编码器
*
* @return
*/
@bean
public passwordencoder passwordencoder() {
return new bcryptpasswordencoder();
}
@bean
public securityfilterchain securityfilterchain(httpsecurity http) throws exception {
//关闭csrf防护,否则回导致登录失败
http.csrf(a -> a.disable()); //禁用scrf
//配置安全拦截规则
http.authorizehttprequests(req ->
req.requestmatchers(ignoredurl.geturls())
.permitall()
.anyrequest().authenticated());
/**
* 配置登录页
*/
http.formlogin(form -> form
.loginpage("/")
.successforwardurl("/index") //登录成功跳转页面
.loginprocessingurl("/login")//登录处理url
.failureforwardurl("/error") //登录失败跳转页面
// .usernameparameter("name")//自定义用户名参数
// .passwordparameter("password")//自定义密码参数
);
return http.build();
}
}@component
public class jwtutils {
@value("${jwt.secret}")
private string secret;
@value("${jwt.expiration}")
private integer expiration;
/**
*
*/
public string generatetoken(authentication authentication) {
date now = new date();
date expirationdate = dateutil.offsetsecond(now, expiration);
map<string, object> claims = new hashmap<>();
claims.put("username", authentication.getname());//用户名
claims.put("exp", expirationdate);
// claims.put();
return jwtutil.createtoken(claims, secret.getbytes());
}
}@component
@data
@configurationproperties(prefix = "security.ignored")
@tostring
public class ignoredurl {
private string[] urls;
}
登录成功

登陆失败

总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论