在我们做SpringBoot项目的时候,认证授权是必不可少的功能!我们经常会选择Shiro、Spring Security这类权限认证框架来实现,但这些框架使用起来有点繁琐,而且功能也不够强大。最近发现一款功能强大的权限认证框架Sa-Token,它使用简单、API设计优雅,推荐给大家!
Sa-Token简介 Sa-Token是一款轻量级的Java权限认证框架,可以用来解决登录认证、权限认证、Session会话、单点登录、OAuth2.0、微服务网关鉴权等一系列权限相关问题。
框架集成简单、开箱即用、API设计优雅,通过Sa-Token,你将以一种极其简单的方式实现系统的权限认证部分,有时候往往只需一行代码就能实现功能。
Sa-Token功能很全,具体可以参考下图。
使用 在SpringBoot中使用Sa-Token是非常简单的,接下来我们使用它来实现最常用的认证授权功能,包括登录认证、角色认证和权限认证。
集成及配置 Sa-Token的集成和配置都非常简单,不愧为开箱即用。
<!-- Sa-Token 权限认证 -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.24.0</version>
</dependency>
# 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中读取tokenis-read-cookie: false# 是否从head中读取tokenis-read-head: true
登录认证 在管理系统中,除了登录接口,基本都需要登录认证,在Sa-Token中使用路由拦截鉴权是最方便的,下面我们来实现下。
/*** 后台用户管理* Created by macro on 2018/4/26.*/
@Controller
@Api(tags = "UmsAdminController", description = "后台用户管理")
@RequestMapping("/admin")
public class UmsAdminController {@Autowiredprivate UmsAdminService adminService;@ApiOperation(value = "登录以后返回token")@RequestMapping(value = "/login", method = RequestMethod.POST)@ResponseBodypublic 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);}
}
/*** Created by macro on 2020/10/15.*/
@Slf4j
@Service
public class UmsAdminServiceImpl implements UmsAdminService {@Overridepublic 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;}
}
/*** Created by macro on 2020/10/15.*/
@Slf4j
@Service
public class UmsAdminServiceImpl implements UmsAdminService {@ApiOperation(value = "查询当前登录状态")@RequestMapping(value = "/isLogin", method = RequestMethod.GET)@ResponseBodypublic CommonResult isLogin() {return CommonResult.success(StpUtil.isLogin());}
}
/*** Sa-Token相关配置*/
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {@Autowiredprivate IgnoreUrlsConfig ignoreUrlsConfig;/*** 注册sa-token拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SaRouteInterceptor((req, resp, handler) -> {// 获取配置文件中的白名单路径List<String> ignoreUrls = ignoreUrlsConfig.getUrls();// 登录认证:除白名单路径外均需要登录认证SaRouter.match(Collections.singletonList("/**"), ignoreUrls, StpUtil::checkLogin);})).addPathPatterns("/**");}
}
# 访问白名单路径
secure:ignored:urls:- /- /swagger-ui/- /*.html- /favicon.ico- /**/*.html- /**/*.css- /**/*.js- /swagger-resources/**- /v2/api-docs/**- /actuator/**- /admin/login- /admin/isLogin
/*** 全局异常处理* Created by macro on 2020/2/27.*/
@ControllerAdvice
public class GlobalExceptionHandler {/*** 处理未登录的异常*/@ResponseBody@ExceptionHandler(value = NotLoginException.class)public CommonResult handleNotLoginException(NotLoginException e) {return CommonResult.unauthorized(e.getMessage());}
}
角色认证 角色认证也就是我们定义好一套规则,比如ROLE-ADMIN角色可以访问/brand下的所有资源,而ROLE_USER角色只能访问/brand/listAll,接下来我们来实现下角色认证。
/*** 自定义权限验证接口扩展*/
@Component
public class StpInterfaceImpl implements StpInterface {@Autowiredprivate UmsAdminService adminService;@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {AdminUser adminUser = adminService.getAdminById(Convert.toLong(loginId));return adminUser.getRole().getPermissionList();}@Overridepublic List<String> getRoleList(Object loginId, String loginType) {AdminUser adminUser = adminService.getAdminById(Convert.toLong(loginId));return Collections.singletonList(adminUser.getRole().getName());}
}
/*** Sa-Token相关配置*/
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {@Autowiredprivate IgnoreUrlsConfig ignoreUrlsConfig;/*** 注册sa-token拦截器*/@Overridepublic 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("/**");}
}
/*** 全局异常处理* Created by macro on 2020/2/27.*/
@ControllerAdvice
public class GlobalExceptionHandler {/*** 处理没有角色的异常*/@ResponseBody@ExceptionHandler(value = NotRoleException.class)public CommonResult handleNotRoleException(NotRoleException e) {return CommonResult.forbidden(e.getMessage());}
}
权限认证 当我们给角色分配好权限,然后给用户分配好角色后,用户就拥有了这些权限。我们可以为每个接口分配不同的权限,拥有该权限的用户就可以访问该接口。这就是权限认证,接下来我们来实现下它。
/*** Sa-Token相关配置*/
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {@Autowiredprivate IgnoreUrlsConfig ignoreUrlsConfig;/*** 注册sa-token拦截器*/@Overridepublic 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("/**");}
}
/*** 全局异常处理* Created by macro on 2020/2/27.*/
@ControllerAdvice
public class GlobalExceptionHandler {/*** 处理没有权限的异常*/@ResponseBody@ExceptionHandler(value = NotPermissionException.class)public CommonResult handleNotPermissionException(NotPermissionException e) {return CommonResult.forbidden(e.getMessage());}
}
总结 通过对Sa-Token的一波实践,我们可以发现它的API设计非常优雅,比起Shiro和Spring Security来说确实顺手多了。Sa-Token不仅提供了一系列强大的权限相关功能,还提供了很多标准的解决方案,比如Oauth2、分布式Session会话等,大家感兴趣的话可以研究下。
参考资料 Sa-Token的官方文档很全,也很良心,不仅提供了解决方式,还提供了解决思路,强烈建议大家去看下。
官方文档:http://sa-token.dev33.cn/
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道 公众号
好文章,我在看❤️
总结
以上是生活随笔 为你收集整理的再见Spring Security!推荐一款功能强大的权限认证框架,用起来够优雅! 的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔 网站内容还不错,欢迎将生活随笔 推荐给好友。