简单的单点登录,目前可以基于 solon.sessionstate.jwt 插件实现。假定场景是多个管理后台,使用二级域名分别为:
- a.demo.org
- b.demo.org
- c.demo.org
各个管理后台,在一个导航页面上。在导航页面上的链接("/login"),用户点击后,如果是已登录跳到管理页,未登录显示登录页。
1、简单的流程设计
- 跳到登录页。如果有发现已登录,而跳到当前用户上次打开的页面;否则显示登录界面
- 登录页。登录成功后,在 sessin 里登记用户标识
- 管理页。使用验证插件的登录验证注解。(实战时,用签权框架更合适)
2、方案实现
1)添加配置
#可共享域配置(可不配,默认当前服务域名;多系统共享时要配置)
server.session.state.domain: "demo.org" #用一级域名
#Jwt 密钥(使用 JwtUtils.createKey() 生成)
server.session.state.jwt.secret: "E3F9N2kRDQf55pnJPnFoo5+ylKmZQ7AXmWeOVPKbEd8="
2)实现登录相关控制
登录与退出控制(jwt 会通过 cookie 传,不用管细节)
@Controller
public class LoginController {
//登录
@Mapping("/login")
public ModelAndView login(Context ctx){
if(ctx.sessionAsLong("user_id", 0L) > 0){
//跳到管理后台主页(或者打开cookie记住的最近请求页面)
ctx.redirect("/admin/main");
return null;
}else{
//显示登录界面
return new ModelAndView("/login");
}
}
//登录处理
@Mapping("/login/ajax/do")
public Result loginAjaxDo(Context ctx, String username, String password){
if (username == "test" && password == "1234") {
//获取登录的用户id
long userId = 1001;
//登录
ctx.sessionSet("user_id", userId);
return Result.succeed();
}else{
return Result.failure();
}
}
//退出页
@Mapping("logout")
public void logout(Context ctx) {
ctx.sessionClear();
}
}
3)与验证器插件 solon.validation 的登录验证做结合(实战时,用签权框架更合适)
配置登录注解的检测器
@Configuration
public class Config {
@Bean
public LoginedChecker loginedChecker() {
return (anno, ctx, userKeyName) -> ctx.sessionAsLong("user_id", 0L) > 0;
}
}
再加个登录验证器出错的处理,未登录的自动跳到登录页
//可以和其它异常处理合并一个过滤器
@Component
public class ValidatorFailureFilter implements Filter {
@Override
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
try {
chain.doFilter(ctx);
} catch (ValidatorException e) {
if(e.getAnnotation() instanceof Logined){
ctx.redirect("/login"); //如果验证出错的是 Logined 注解,则跳到登录页上
}else {
ctx.render(Result.failure(e.getCode(), e.getMessage()));
}
}
}
}
4)登录验证注解在管理页的使用
@Logined //可以使用验证注解了
@Mapping("admin")
@Controller
public class AdminController extends BaseController{
@Mapping("test")
public String test(){
return "OK";
}
}