spring-security实现的token授权
程序员文章站
2022-07-11 10:32:57
在我的用户密码授权文章里介绍了spring security的工作过程,不了解的同学,可以先看看 "用户密码授权" 这篇文章,在 用户密码授权模式里,主要是通过一个登陆页进行授权,然后把授权对象写到session里,它主要用在mvc框架里,而对于webapi来说,一般不会采用这种方式,对于webap ......
在我的用户密码授权文章里介绍了spring-security的工作过程,不了解的同学,可以先看看这篇文章,在
用户密码授权模式里,主要是通过一个登陆页进行授权,然后把授权对象写到session里,它主要用在mvc框架里,而对于webapi来说,一般不会采用这种方式,对于webapi
来说,一般会用jwt授权方式,就是token授权码的方式,每访问api接口时,在http头上带着你的token码,而大叔自己也写了一个简单的jwt授权模式,下面介绍一下。
websecurityconfig授权配置
@configuration @enablewebsecurity @enableglobalmethodsecurity(prepostenabled = true) public class tokenwebsecurityconfig extends websecurityconfigureradapter { /** * token过滤器. */ @autowired lindtokenauthenticationfilter lindtokenauthenticationfilter; @bean @override public authenticationmanager authenticationmanagerbean() throws exception { return super.authenticationmanagerbean(); } @override protected void configure(httpsecurity httpsecurity) throws exception { httpsecurity .csrf().disable() // 基于token,所以不需要session .sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless).and() .authorizerequests() // 对于获取token的rest api要允许匿名访问 .antmatchers("/lind-auth/**").permitall() // 除上面外的所有请求全部需要鉴权认证 .anyrequest().authenticated(); httpsecurity .addfilterbefore(lindtokenauthenticationfilter, usernamepasswordauthenticationfilter.class); // 禁用缓存 httpsecurity.headers().cachecontrol(); } /** * 密码生成策略. * * @return */ @bean public passwordencoder passwordencoder() { return new bcryptpasswordencoder(); } }
授权接口login
对外开放的,需要提供用户名和密码为参数进行登陆,然后返回token码,当然也可以使用手机号和验证码登陆,授权逻辑是一样的,获取用户信息都是使用userdetailsservice
,
然后开发人员根据自己的业务去重写loaduserbyusername
来获取用户实体。
用户登陆成功后,为它授权及认证,这一步我们会在redis里建立token与用户名的关系。
@getmapping(login) public responseentity<?> refreshandgetauthenticationtoken( @requestparam string username, @requestparam string password) throws authenticationexception { return responseentity.ok(generatetoken(username, password)); } /** * 登陆与授权. * * @param username . * @param password . * @return */ private string generatetoken(string username, string password) { usernamepasswordauthenticationtoken uptoken = new usernamepasswordauthenticationtoken(username, password); // perform the security final authentication authentication = authenticationmanager.authenticate(uptoken); securitycontextholder.getcontext().setauthentication(authentication); // reload password post-security so we can generate token final userdetails userdetails = userdetailsservice.loaduserbyusername(username); // 持久化的redis string token = commonutils.encrypt(userdetails.getusername()); redistemplate.opsforvalue().set(token, userdetails.getusername()); return token; }
lindtokenauthenticationfilter代码
主要实现了对请求的拦截,获取http头上的authorization
元素,token码就在这个键里,我们的token都是采用通用的bearer
开头,当你的token没有过期时,会
存储在redis里,key就是用户名的md5码,而value就是用户名,当拿到token之后去数据库或者缓存里拿用户信息进行授权即可。
/** * token filter bean. */ @component public class lindtokenauthenticationfilter extends onceperrequestfilter { @autowired redistemplate<string, string> redistemplate; string tokenhead = "bearer "; string tokenheader = "authorization"; @autowired private userdetailsservice userdetailsservice; /** * token filter. * * @param request . * @param response . * @param filterchain . */ @override protected void dofilterinternal( httpservletrequest request, httpservletresponse response, filterchain filterchain) throws servletexception, ioexception { string authheader = request.getheader(this.tokenheader); if (authheader != null && authheader.startswith(tokenhead)) { final string authtoken = authheader.substring(tokenhead.length()); // the part after "bearer " if (authtoken != null && redistemplate.haskey(authtoken)) { string username = redistemplate.opsforvalue().get(authtoken); if (username != null && securitycontextholder.getcontext().getauthentication() == null) { userdetails userdetails = this.userdetailsservice.loaduserbyusername(username); //可以校验token和username是否有效,目前由于token对应username存在redis,都以默认都是有效的 usernamepasswordauthenticationtoken authentication = new usernamepasswordauthenticationtoken( userdetails, null, userdetails.getauthorities()); authentication.setdetails(new webauthenticationdetailssource().builddetails( request)); logger.info("authenticated user " + username + ", setting security context"); securitycontextholder.getcontext().setauthentication(authentication); } } } filterchain.dofilter(request, response); }
测试token授权
get:http://localhost:8080/lind-demo/login?username=admin&password=123 post:http://localhost:8080/lind-demo/user/add content-type:application/json authorization:bearer 21232f297a57a5a743894a0e4a801fc3