You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Tomcat Form based authentication的Ember应用登录跳转异常咨询

嘿,作为Ember新手碰到Tomcat表单认证的问题很正常,我来一步步帮你搞定!

第一步:先搞定Tomcat端的web.xml配置

Tomcat的表单认证核心都在Web应用的web.xml里,你需要正确定义受保护资源、登录规则和安全角色。给你一个实用的配置示例:

<!-- 定义哪些资源需要保护 -->
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Protected API</web-resource-name>
        <!-- 这里填你后端需要保护的API路径,比如所有/api/protected开头的接口 -->
        <url-pattern>/api/protected/*</url-pattern>
        <!-- 如果你的前端路由也需要保护,注意SPA特性,通常我们优先保护后端API,前端路由由Ember自己拦截 -->
    </web-resource-collection>
    <auth-constraint>
        <!-- 允许访问的角色,后面要对应下面的security-role -->
        <role-name>authenticated-user</role-name>
    </auth-constraint>
</security-constraint>

<!-- 配置表单登录规则 -->
<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <!-- Tomcat会在用户未认证时跳转到这个路径,填Ember的登录前端路由,比如/login -->
        <form-login-page>/login</form-login-page>
        <!-- 登录失败后的跳转路径 -->
        <form-error-page>/login?error=true</form-error-page>
    </form-login-config>
</login-config>

<!-- 定义安全角色 -->
<security-role>
    <role-name>authenticated-user</role-name>
</security-role>

注意:如果你的Ember应用部署在Tomcat的子目录下(比如/my-app),那form-login-page要写成/my-app/login,确保路径正确。

第二步:配置Ember的登录表单

Tomcat的表单认证有固定的要求:表单提交地址必须是j_security_check,用户名输入框的name是j_username,密码输入框的name是j_password。所以你的Ember登录模板(比如app/templates/login.hbs)要这么写:

<form action="{{rootURL}}j_security_check" method="POST">
    <div class="form-group">
        <label>用户名</label>
        <input type="text" name="j_username" required>
    </div>
    <div class="form-group">
        <label>密码</label>
        <input type="password" name="j_password" required>
    </div>
    {{#if @model.error}}
        <p class="error-message">登录失败,请检查用户名和密码</p>
    {{/if}}
    <button type="submit">登录</button>
</form>

这里的rootURL要和你Ember项目config/environment.js里的rootURL保持一致,确保表单能正确提交到Tomcat的认证接口。

第三步:Ember路由的认证拦截(关键!)

因为Ember是单页应用,前端路由本身不会触发Tomcat的认证跳转——你直接访问受保护的前端路由时,Ember会直接加载页面,但此时后端API还没被调用,所以你需要在Ember的路由里手动添加认证检查:

比如,创建一个基础的受保护路由类,所有需要认证的路由都继承它:

// app/routes/protected-base.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class ProtectedBaseRoute extends Route {
  @service ajax; // 如果你用ember-ajax,或者直接用fetch也可以

  async beforeModel(transition) {
    try {
      // 调用一个后端的"检查认证状态"接口,比如获取当前用户信息
      await this.ajax.request('/api/current-user');
      // 如果请求成功,说明已认证,继续加载路由
    } catch (error) {
      // 如果返回401未授权,跳转到登录路由,并保存当前的跳转状态
      this.set('previousTransition', transition);
      this.transitionTo('login');
      transition.abort();
    }
  }
}

然后你的受保护路由(比如app/routes/dashboard.js)就继承这个基础类:

// app/routes/dashboard.js
import ProtectedBaseRoute from './protected-base';

export default class DashboardRoute extends ProtectedBaseRoute {
  // 你的路由逻辑
}
第四步:登录成功后的跳转处理

当用户登录成功后,Tomcat会跳转到你在form-login-config里设置的成功页面,或者默认跳转到之前请求的受保护资源。为了让Ember正确跳转回用户最初访问的页面,你可以在登录路由里添加逻辑:

// app/routes/login.js
import Route from '@ember/routing/route';

export default class LoginRoute extends Route {
  beforeModel(transition) {
    // 保存用户原本要访问的路由(如果不是直接访问登录页的话)
    if (transition.intent.name !== 'login') {
      this.set('previousTransition', transition);
    }
    // 如果有登录错误参数,传给模板显示
    let error = this.paramsFor('login').error;
    this.set('error', error);
  }

  model() {
    return { error: this.get('error') };
  }

  afterModel() {
    // 登录成功后,跳回之前的路由,或者默认跳转到首页
    let previousTransition = this.get('previousTransition');
    if (previousTransition) {
      this.set('previousTransition', null);
      previousTransition.retry();
    } else {
      this.transitionTo('index');
    }
  }
}
常见坑点提醒
  • 确保web.xml里的url-pattern正确匹配了你的后端API,不要写错路径;
  • 登录表单的name属性必须是j_usernamej_password,Tomcat认这个,改了就没用;
  • Ember的rootURL配置要和Tomcat里的部署路径一致,避免表单提交路径错误;
  • 如果是开发环境用ember serve,后端Tomcat在另一个端口,会有跨域问题,这时候需要在Tomcat里配置CORS(不过你是部署在Tomcat里的话,应该不存在这个问题)。

内容的提问来源于stack exchange,提问作者Abdul

火山引擎 最新活动