// 会话登录接口
@RequestMapping("doLogin")
public SaResult doLogin(String name, String pwd) {
// 第一步:比对前端提交的账号名称、密码
if("zhang".equals(name) && "123456".equals(pwd)) {
// 第二步:根据账号id,进行登录
StpUtil.login(10001);
return SaResult.ok("登录成功");
}
return SaResult.error("登录失败");
}
此处仅仅做了会话登录,但并没有主动向前端返回 Token 信息。 是因为不需要吗?严格来讲是需要的,只不过 StpUtil.login(id)
方法利用了 Cookie 自动注入的特性,省略了你手写返回 Token 的代码。
// 当前会话注销登录
StpUtil.logout();
// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();
// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();
1、强制注销
StpUtil.logout(10001); // 强制指定账号注销下线 StpUtil.logout(10001, "PC"); // 强制指定账号指定端注销下线 StpUtil.logoutByTokenValue("token"); // 强制指定 Token 注销下线
2、踢人下线
StpUtil.kickout(10001); // 将指定账号踢下线 StpUtil.kickout(10001, "PC"); // 将指定账号指定端踢下线 StpUtil.kickoutByTokenValue("token"); // 将指定 Token 踢下线
强制注销 和 踢人下线 的区别在于:
因为每个项目的需求不同,其权限设计也千变万化,因此 [ 获取当前账号权限码集合 ] 这一操作不可能内置到框架中, 所以 Sa-Token 将此操作以接口的方式暴露给你,以方便你根据自己的业务逻辑进行重写。
你需要做的就是新建一个类,实现 StpInterface
接口,例如以下代码:
/** * 自定义权限验证接口扩展 */ @Component // 保证此类被SpringBoot扫描,完成Sa-Token的自定义权限验证扩展 public class StpInterfaceImpl implements StpInterface { /** * 返回一个账号所拥有的权限码集合 */ @Override public List
getPermissionList(Object loginId, String loginType) { // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限 List list = new ArrayList (); list.add("101"); list.add("user.add"); list.add("user.update"); list.add("user.get"); // list.add("user.delete"); list.add("art.*"); return list; } /** * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验) */ @Override public List getRoleList(Object loginId, String loginType) { // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色 List list = new ArrayList (); list.add("admin"); list.add("super-admin"); return list; } }
在Sa-Token中,角色和权限可以独立验证
// 获取:当前账号所拥有的角色集合 StpUtil.getRoleList(); // 判断:当前账号是否拥有指定角色, 返回 true 或 false StpUtil.hasRole("super-admin"); // 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException StpUtil.checkRole("super-admin"); // 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] StpUtil.checkRoleAnd("super-admin", "shop-admin"); // 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] StpUtil.checkRoleOr("super-admin", "shop-admin");
有同学要问,鉴权失败,抛出异常,然后呢?要把异常显示给用户看吗?当然不可以!
你可以创建一个全局异常拦截器,统一返回给前端的格式,参考:
@RestControllerAdvice public class GlobalExceptionHandler { // 全局异常拦截 @ExceptionHandler public SaResult handlerException(Exception e) { e.printStackTrace(); return SaResult.error(e.getMessage()); } }
Sa-Token允许你根据通配符指定泛权限,例如当一个账号拥有art.*
的权限时,art.add
、art.delete
、art.update
都将匹配通过
// 当拥有 art.* 权限时 StpUtil.hasPermission("art.add"); // true StpUtil.hasPermission("art.update"); // true StpUtil.hasPermission("goods.add"); // false // 当拥有 *.delete 权限时 StpUtil.hasPermission("art.delete"); // true StpUtil.hasPermission("user.delete"); // true StpUtil.hasPermission("user.update"); // false // 当拥有 *.js 权限时 StpUtil.hasPermission("index.js"); // true StpUtil.hasPermission("index.css"); // false StpUtil.hasPermission("index.html"); // false
导入依赖:
cn.dev33
sa-token-spring-boot-starter
1.34.0
添加拦截器:
@Configuration
public class SSOInterceptorCustom implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将satoken的注解拦截器加入mvc
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
}
控制层:
package com.sunjob.authssoservice.controller;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/sso")
public class LoginController {
// 登录认证
@RequestMapping("/login")
public Object userLogin(@RequestParam("username") String uname,
@RequestParam("upwd") String upwd)
{
if(!StpUtil.isDisable(uname))//账号没有被封禁
{
StpUtil.login(uname); //完成登录认证
return StpUtil.getTokenInfo().tokenValue;//返回token
}
// StpUtil.getDisableTime(uname)账号封禁时间
return "你的账号已经被封禁。"+(StpUtil.getDisableTime(uname) == -1?"永久封禁":StpUtil.getDisableTime(uname));
}
// 查看用户是否登录
@RequestMapping("/checklogin")
public Object checkLogin()
{
// StpUtil.checkLogin();//判断当前是否有用户登录-中断式判断和中断式判断
// StpUtil.isLogin();//判断当前是否有用户登录-中断式判断和非中断式判断 返回布尔类型
return StpUtil.isLogin()?"登陆成功":"未登录";
}
// 登录用户信息
@RequestMapping("/logininfo")
public Object returnlogininfo()
{
Map info=new HashMap();
info.put("tokeninfo",StpUtil.getTokenInfo());
info.put("userinfo",StpUtil.getLoginId());
info.put("session",StpUtil.getSession());
return info;
}
// 踢人下线
@RequestMapping("/kick")
public Object kickuser(@RequestParam("username") String uname)
{
StpUtil.kickout(uname);
return "已经下线";
}
// 封禁帐户
@RequestMapping("/banuser")
public Object banuser(@RequestParam("username") String uname)
{
StpUtil.getPermissionList().forEach((v)-> System.out.println(v));//拿到当前用户的所有权限
boolean a=StpUtil.hasPermission("user.add");
boolean b=StpUtil.hasPermissionAnd("user.delete","user.qry");
boolean c=StpUtil.hasPermissionOr("user.add","user.update");
System.out.println(a+"==="+b+"==="+c);
boolean r = StpUtil.hasRole("董事长");
if (r){
StpUtil.disable(uname,-1);//以秒为单位,86400 1天 -1为永久封禁
return "账号已经被封禁成功";
}
else
{
String roles = "";
for (String s : StpUtil.getRoleList()) {
roles+=s+",";
}
return "你的角色不能封禁账号,你拥有角色如下"+roles+",账号封禁需要董事长角色。";
}
}
}
package com.sunjob.authssoservice.impl;
import cn.dev33.satoken.stp.StpInterface;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class UserRoleCheckImpl implements StpInterface {
// 需要验证的权限列表初始化
@Override
public List getPermissionList(Object o, String s) {
// 需要验证的权限列表初始化
List auths=new ArrayList<>();
auths.add("user.add");
auths.add("user.delete");
auths.add("user.update");
auths.add("user.qry");
return auths;
}
@Override
public List getRoleList(Object o, String s) {
// 需要验证的角色列表初始化
List auths=new ArrayList<>();
auths.add("经理");
auths.add("总监");
auths.add("董事长");
auths.add("秘书");
return auths;
}
}
前端界面:
用户名:
密码:
登录
查看登录状态
查看信息
踢人下线
封禁
登出