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; }
登录成功
登陆失败
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论