在咱们做SpringBoot我的项目的时候,认证受权是必不可少的性能!咱们常常会抉择Shiro、Spring Security这类权限认证框架来实现,但这些框架应用起来有点繁琐,而且性能也不够弱小。最近发现一款功能强大的权限认证框架Sa-Token,它应用简略、API设计优雅,举荐给大家!
SpringBoot实战电商我的项目mall(50k+star)地址:https://github.com/macrozheng/mall
Sa-Token简介
Sa-Token是一款轻量级的Java权限认证框架,能够用来解决登录认证、权限认证、Session会话、单点登录、OAuth2.0、微服务网关鉴权等一系列权限相干问题。
框架集成简略、开箱即用、API设计优雅,通过Sa-Token,你将以一种极其简略的形式实现零碎的权限认证局部,有时候往往只需一行代码就能实现性能。
Sa-Token性能很全,具体能够参考下图。
应用
在SpringBoot中应用Sa-Token是非常简单的,接下来咱们应用它来实现最罕用的认证受权性能,包含登录认证、角色认证和权限认证。
集成及配置
Sa-Token的集成和配置都非常简单,不愧为开箱即用。
- 首先咱们须要在我的项目的
pom.xml
中增加Sa-Token的相干依赖;
<!-- Sa-Token 权限认证 --><dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.24.0</version></dependency>
- 而后在
application.yml
中增加Sa-Token的相干配置,思考到要反对前后端拆散我的项目,咱们敞开从cookie中读取token,改为从head中读取token。
# Sa-Token配置sa-token: # token名称 (同时也是cookie名称) token-name: Authorization # token有效期,单位秒,-1代表永不过期 timeout: 2592000 # token长期有效期 (指定工夫内无操作就视为token过期),单位秒 activity-timeout: -1 # 是否容许同一账号并发登录 (为false时新登录挤掉旧登录) is-concurrent: true # 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token) is-share: false # token格调 token-style: uuid # 是否输入操作日志 is-log: false # 是否从cookie中读取token is-read-cookie: false # 是否从head中读取token is-read-head: true
登录认证
在管理系统中,除了登录接口,根本都须要登录认证,在Sa-Token中应用路由拦挡鉴权是最不便的,上面咱们来实现下。
- 实现登录认证非常简单,首先在
UmsAdminController
中增加一个登录接口;
/** * 后盾用户治理 * Created by macro on 2018/4/26. */@Controller@Api(tags = "UmsAdminController", description = "后盾用户治理")@RequestMapping("/admin")public class UmsAdminController { @Autowired private UmsAdminService adminService; @ApiOperation(value = "登录当前返回token") @RequestMapping(value = "/login", method = RequestMethod.POST) @ResponseBody public CommonResult login(@RequestParam String username, @RequestParam String password) { SaTokenInfo saTokenInfo = adminService.login(username, password); if (saTokenInfo == null) { return CommonResult.validateFailed("用户名或明码谬误"); } Map<String, String> tokenMap = new HashMap<>(); tokenMap.put("token", saTokenInfo.getTokenValue()); tokenMap.put("tokenHead", saTokenInfo.getTokenName()); return CommonResult.success(tokenMap); }}
- 而后在
UmsAdminServiceImpl
增加登录的具体逻辑,先验证明码,而后调用StpUtil.login(adminUser.getId())
即可实现登录,调用API一行搞定;
/** * Created by macro on 2020/10/15. */@Slf4j@Servicepublic class UmsAdminServiceImpl implements UmsAdminService { @Override public SaTokenInfo login(String username, String password) { SaTokenInfo saTokenInfo = null; AdminUser adminUser = getAdminByUsername(username); if (adminUser == null) { return null; } if (!SaSecureUtil.md5(password).equals(adminUser.getPassword())) { return null; } // 明码校验胜利后登录,一行代码实现登录 StpUtil.login(adminUser.getId()); // 获取以后登录用户Token信息 saTokenInfo = StpUtil.getTokenInfo(); return saTokenInfo; }}
- 咱们再增加一个测试接口用于查问以后登录状态,返回
true
示意曾经登录;
/** * Created by macro on 2020/10/15. */@Slf4j@Servicepublic class UmsAdminServiceImpl implements UmsAdminService { @ApiOperation(value = "查问以后登录状态") @RequestMapping(value = "/isLogin", method = RequestMethod.GET) @ResponseBody public CommonResult isLogin() { return CommonResult.success(StpUtil.isLogin()); }}
- 之后能够通过Swagger拜访登录接口来获取Token了,应用账号为
admin:123456
,拜访地址:http://localhost:8088/swagger...
- 而后在
Authorization
申请头中增加获取到的token;
- 拜访
/admin/isLogin
接口,data
属性就会返回true
了,示意你曾经是登录状态了;
- 接下来咱们须要把除登录接口以外的接口都增加登录认证,增加Sa-Token的Java配置类
SaTokenConfig
,注册一个路由拦截器SaRouteInterceptor
,这里咱们的IgnoreUrlsConfig
配置会从配置文件中读取白名单配置;
/** * Sa-Token相干配置 */@Configurationpublic class SaTokenConfig implements WebMvcConfigurer { @Autowired private IgnoreUrlsConfig ignoreUrlsConfig; /** * 注册sa-token拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SaRouteInterceptor((req, resp, handler) -> { // 获取配置文件中的白名单门路 List<String> ignoreUrls = ignoreUrlsConfig.getUrls(); // 登录认证:除白名单门路外均须要登录认证 SaRouter.match(Collections.singletonList("/**"), ignoreUrls, StpUtil::checkLogin); })).addPathPatterns("/**"); }}
application.yml
文件中的白名单配置如下,留神凋谢Swagger的拜访门路和动态资源门路;
# 拜访白名单门路secure: ignored: urls: - / - /swagger-ui/ - /*.html - /favicon.ico - /**/*.html - /**/*.css - /**/*.js - /swagger-resources/** - /v2/api-docs/** - /actuator/** - /admin/login - /admin/isLogin
- 因为未登录状态下拜访接口,Sa-Token会抛出
NotLoginException
异样,所以咱们须要全局解决下;
/** * 全局异样解决 * Created by macro on 2020/2/27. */@ControllerAdvicepublic class GlobalExceptionHandler { /** * 解决未登录的异样 */ @ResponseBody @ExceptionHandler(value = NotLoginException.class) public CommonResult handleNotLoginException(NotLoginException e) { return CommonResult.unauthorized(e.getMessage()); }}
- 之后当咱们在登录状态下拜访接口时,能够获取到数据;
- 当咱们未登录状态(不带token)时无奈失常拜访接口,返回
code
为401
。
角色认证
角色认证也就是咱们定义好一套规定,比方ROLE-ADMIN
角色能够拜访/brand
下的所有资源,而ROLE_USER
角色只能拜访/brand/listAll
,接下来咱们来实现下角色认证。
- 首先咱们须要扩大Sa-Token的
StpInterface
接口,通过实现办法来返回用户的角色码和权限码;
/** * 自定义权限验证接口扩大 */@Componentpublic class StpInterfaceImpl implements StpInterface { @Autowired private UmsAdminService adminService; @Override public List<String> getPermissionList(Object loginId, String loginType) { AdminUser adminUser = adminService.getAdminById(Convert.toLong(loginId)); return adminUser.getRole().getPermissionList(); } @Override public List<String> getRoleList(Object loginId, String loginType) { AdminUser adminUser = adminService.getAdminById(Convert.toLong(loginId)); return Collections.singletonList(adminUser.getRole().getName()); }}
- 而后在Sa-Token的拦截器中配置路由规定,
ROLE_ADMIN
角色能够拜访所有门路,而ROLE_USER
只能拜访/brand/listAll
门路;
/** * Sa-Token相干配置 */@Configurationpublic class SaTokenConfig implements WebMvcConfigurer { @Autowired private IgnoreUrlsConfig ignoreUrlsConfig; /** * 注册sa-token拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SaRouteInterceptor((req, resp, handler) -> { // 获取配置文件中的白名单门路 List<String> ignoreUrls = ignoreUrlsConfig.getUrls(); // 登录认证:除白名单门路外均须要登录认证 SaRouter.match(Collections.singletonList("/**"), ignoreUrls, StpUtil::checkLogin); // 角色认证:ROLE_ADMIN能够拜访所有接口,ROLE_USER只能拜访查问全副接口 SaRouter.match("/brand/listAll", () -> { StpUtil.checkRoleOr("ROLE_ADMIN","ROLE_USER"); //强制退出匹配链 SaRouter.stop(); }); SaRouter.match("/brand/**", () -> StpUtil.checkRole("ROLE_ADMIN")); })).addPathPatterns("/**"); }}
- 当用户不是被容许的角色拜访时,Sa-Token会抛出
NotRoleException
异样,咱们能够全局解决下;
/** * 全局异样解决 * Created by macro on 2020/2/27. */@ControllerAdvicepublic class GlobalExceptionHandler { /** * 解决没有角色的异样 */ @ResponseBody @ExceptionHandler(value = NotRoleException.class) public CommonResult handleNotRoleException(NotRoleException e) { return CommonResult.forbidden(e.getMessage()); }}
- 咱们当初有两个用户,
admin
用户具备ROLE_ADMIN
角色,macro
用户具备ROLE_USER
角色;
- 应用
admin
账号拜访/brand/list
接口能够失常拜访;
- 应用
macro
账号拜访/brand/list
接口无奈失常拜访,返回code
为403
。
权限认证
当咱们给角色调配好权限,而后给用户调配好角色后,用户就领有了这些权限。咱们能够为每个接口调配不同的权限,领有该权限的用户就能够拜访该接口。这就是权限认证,接下来咱们来实现下它。
- 咱们能够在Sa-Token的拦截器中配置路由规定,
admin
用户能够拜访所有门路,而macro
用户只有读取的权限,没有写、改、删的权限;
/** * Sa-Token相干配置 */@Configurationpublic class SaTokenConfig implements WebMvcConfigurer { @Autowired private IgnoreUrlsConfig ignoreUrlsConfig; /** * 注册sa-token拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SaRouteInterceptor((req, resp, handler) -> { // 获取配置文件中的白名单门路 List<String> ignoreUrls = ignoreUrlsConfig.getUrls(); // 登录认证:除白名单门路外均须要登录认证 SaRouter.match(Collections.singletonList("/**"), ignoreUrls, StpUtil::checkLogin); // 权限认证:不同接口, 校验不同权限 SaRouter.match("/brand/listAll", () -> StpUtil.checkPermission("brand:read")); SaRouter.match("/brand/create", () -> StpUtil.checkPermission("brand:create")); SaRouter.match("/brand/update/{id}", () -> StpUtil.checkPermission("brand:update")); SaRouter.match("/brand/delete/{id}", () -> StpUtil.checkPermission("brand:delete")); SaRouter.match("/brand/list", () -> StpUtil.checkPermission("brand:read")); SaRouter.match("/brand/{id}", () -> StpUtil.checkPermission("brand:read")); })).addPathPatterns("/**"); }}
- 当用户无权限拜访时,Sa-Token会抛出
NotPermissionException
异样,咱们能够全局解决下;
/** * 全局异样解决 * Created by macro on 2020/2/27. */@ControllerAdvicepublic class GlobalExceptionHandler { /** * 解决没有权限的异样 */ @ResponseBody @ExceptionHandler(value = NotPermissionException.class) public CommonResult handleNotPermissionException(NotPermissionException e) { return CommonResult.forbidden(e.getMessage()); }}
- 应用
admin
账号拜访/brand/delete
接口能够失常拜访;
- 应用
macro
账号拜访/brand/delete
无奈失常拜访,返回code
为403
。
总结
通过对Sa-Token的一波实际,咱们能够发现它的API设计十分优雅,比起Shiro和Spring Security来说的确棘手多了。Sa-Token不仅提供了一系列弱小的权限相干性能,还提供了很多规范的解决方案,比方Oauth2、分布式Session会话等,大家感兴趣的话能够钻研下。
参考资料
Sa-Token的官网文档很全,也很良心,不仅提供了解决形式,还提供了解决思路,强烈建议大家去看下。
官网文档:http://sa-token.dev33.cn/
我的项目源码地址
https://github.com/macrozheng...
本文 GitHub https://github.com/macrozheng/mall-learning 曾经收录,欢送大家Star!