什么是Sa-Token
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:**
登录认证
、
权限认证
、
Session会话
、
单点登录
、
OAuth2.0
、
微服务网关鉴权
** 等一系列权限相关问题。
快速使用
引入Maven依赖
<!-- web支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--Sa-Token-Quick-Login 插件 --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-quick-login</artifactId><version>1.33.0</version></dependency>
配置参数
server:port:8080# Sa-Token-Quick-Login 配置sa:# 登录账号name: admin
# 登录密码pwd:123456# 是否自动随机生成账号密码 (此项为true时, name与pwd失效)auto:false# 是否开启全局认证(关闭后将不再强行拦截)auth:true# 登录页标题title: Charles Index 登录
# 是否显示底部版权信息copr:true# 指定拦截路径include: /**# 指定排除路径exclude: /test
编写Controller
@RestControllerpublicclassTestController{/**
* 不需要认证
*
* @return
*/@GetMapping("test")publicStringtest(){return"test";}/**
* 需要认证
*
* @return
*/@GetMapping("test1")publicStringtest1(){return"test1";}}
测试
由于没有登录,被拦截了,到了登录页面
源码解析
- 引入
sa-token-quick-login
,会加载jar包中的spring.factories
。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.quick.SaQuickInject
SaQuickInject
类上面注解是@Import({SaQuickController.class, SaQuickRegister.class})
,所以会添加SaQuickController
和SaQuickRegister
。SaQuickController
主要是提供登录页面和提供登录接口
@ControllerpublicclassSaQuickController{publicSaQuickController(){}@GetMapping({"/saLogin"})publicStringsaLogin(HttpServletRequest request){
request.setAttribute("cfg",SaQuickManager.getConfig());return"sa-login.html";}@PostMapping({"/doLogin"})@ResponseBodypublicSaResultdoLogin(String name,String pwd){if(!SaFoxUtil.isEmpty(name)&&!SaFoxUtil.isEmpty(pwd)){SaQuickConfig config =SaQuickManager.getConfig();if(name.equals(config.getName())&& pwd.equals(config.getPwd())){StpUtil.login(config.getName());returnSaResult.get(200,"ok",StpUtil.getTokenInfo());}else{returnSaResult.get(500,"账号或密码输入错误",(Object)null);}}else{returnSaResult.get(500,"请输入账号和密码",(Object)null);}}}
SaQuickRegister
是核心,提供了SaServletFilter
。SaServletFilter
用来做拦截认证。
@ConfigurationpublicclassSaQuickRegister{publicSaQuickRegister(){}@Bean@ConfigurationProperties(
prefix ="sa")publicSaQuickConfiggetSaQuickConfig(){returnnewSaQuickConfig();}@Bean@Order(-101)publicSaServletFiltergetSaServletFilter(){return(newSaServletFilter()).addInclude(newString[]{"/**"}).addExclude(newString[]{"/favicon.ico","/saLogin","/doLogin","/sa-res/**"}).setAuth((obj)->{SaRouter.match(SaQuickManager.getConfig().getInclude().split(",")).notMatch(SaQuickManager.getConfig().getExclude().split(",")).check((r)->{if(SaQuickManager.getConfig().getAuth()&&!StpUtil.isLogin()){SaHolder.getRequest().forward("/saLogin");SaRouter.back();}});}).setError((e)->{return e.getMessage();});}}
- 访问
http://localhost:8080/test
,看下SaServletFilter
是如何放行的。
// cn.dev33.satoken.filter.SaServletFilter#doFilterpublicvoiddoFilter(ServletRequest request,ServletResponse response,FilterChain chain)throwsIOException,ServletException{try{SaRouter.match(this.includeList).notMatch(this.excludeList).check((r)->{this.beforeAuth.run((Object)null);this.auth.run((Object)null);});}catch(StopMatchException var6){}catch(Throwable var7){String result = var7 instanceofBackResultException? var7.getMessage():String.valueOf(this.error.run(var7));if(response.getContentType()==null){
response.setContentType("text/plain; charset=utf-8");}
response.getWriter().print(result);return;}
chain.doFilter(request, response);}
- 该auth方法是在
SaQuickRegister
类中定义的。因为/test
是在配置文件中定义的,所以在执行SaRouter.match(SaQuickManager.getConfig().getInclude().split(",")).notMatch(SaQuickManager.getConfig().getExclude().split(","))
后,SaRouterStaff
中的isHit
变量为false,所以SaRouterStaff#check()
不需要执行。
publicSaRouterStaffnotMatch(String... patterns){if(this.isHit){this.isHit =!SaRouter.isMatchCurrURI(patterns);}returnthis;}
test1
方法由于不在exclude
配置中,所以会执行SaRouterStaff#check()
。该方法中主要有两个判断,SaQuickManager.getConfig().getAuth()
和StpUtil.isLogin() == false
。配置中的auth
设置为true,所以第一个判断为true。StpUtil.isLogin()
用来判断是否登录。跟踪到获取到token的方法,获取不到token,返回false,跳转到saLogin
页面。
getTokenValueNotCut:249, StpLogic (cn.dev33.satoken.stp)
getTokenValue:201, StpLogic (cn.dev33.satoken.stp)
getLoginIdDefaultNull:746, StpLogic (cn.dev33.satoken.stp)
isLogin:659, StpLogic (cn.dev33.satoken.stp)
isLogin:282, StpUtil (cn.dev33.satoken.stp)
- 登录方法,
SaQuickController#doLogin()
。创造token,并且存储在客户端。
login:331, StpLogic (cn.dev33.satoken.stp)
login:293, StpLogic (cn.dev33.satoken.stp)
login:135, StpUtil (cn.dev33.satoken.stp)
doLogin:53, SaQuickController (cn.dev33.satoken.quick.web)
publicvoidlogin(Object id,SaLoginModel loginModel){// 1、创建会话 String token =createLoginSession(id, loginModel);// 2、在当前客户端注入Token setTokenValue(token, loginModel);}
- 存储在客户端。先保留一份在
SaStorage
,再存入cookie。
publicvoidsetTokenValue(String tokenValue,SaLoginModel loginModel){if(SaFoxUtil.isEmpty(tokenValue)){return;}// 1. 将 Token 保存到 [存储器] 里 setTokenValueToStorage(tokenValue);// 2. 将 Token 保存到 [Cookie] 里 if(getConfig().getIsReadCookie()){setTokenValueToCookie(tokenValue, loginModel.getCookieTimeout());}// 3. 将 Token 写入到响应头里 if(loginModel.getIsWriteHeaderOrGlobalConfig()){setTokenValueToResponseHeader(tokenValue);}}
- 登录的时候,从cookie中获取token,判断是否过期,如果能获取loginId,则判断是登录状态,
SaTokenDaoDefaultImpl#get
。
@OverridepublicStringget(String key){clearKeyByTimeout(key);return(String)dataMap.get(key);}
本文转载自: https://blog.csdn.net/qq_42985872/article/details/128581188
版权归原作者 秋装什么 所有, 如有侵权,请联系我们删除。
版权归原作者 秋装什么 所有, 如有侵权,请联系我们删除。