SpringSecurity自定义登录接口 & Angular2的安全路由

来源:互联网 发布:淘宝网818 编辑:程序博客网 时间:2024/06/05 14:15

在配置SpringSecurity的项目中,通过配置.authorizeRequests().antMathers("/path/**",....) 来设置哪些路径需要用户权限,哪些可以不登录浏览。但是如果在该项目中部署了Angular2单页应用的话,由于对SpringSecurity来说仅在第一次进入Angular2应用时经过了Security拦截,之后所有的页面跳转均在Angular2的路由管理下完成,因此SpringSecurity无法管理Angular2应用内部的页面权限,此时需要对Angular2的路由进行改造,让Angular2的路由实现类似Security的功能。

登录接口改造

SpringSecurity改造

默认情况下,SpringSecurity通过设置.formLogin() 来定义登录页入口,最后通过登录页的表单提交完成验证,并跳转至首页。在Angular2项目中,若登录页也由Angular2管理,则登录过程需要通过ajax调用接口实现。因此需要自定义一个登录接口完成登录页post表单登录的流程。
通过AuthenticationManager 即可调用内部的验证流程。
代码如下

@AutowiredAuthenticationManager authenticationManager;@ResponseBody@RequestMapping(value="doLogin",method = RequestMethod.POST)public ResultBean doLogin(HttpServletRequest request, HttpServletResponse response,            @RequestParam("userName")String userName,@RequestParam("password") String password){        ResultBean bean = new ResultBean();        try {            // 内部登录请求            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, password,AuthorityUtils.commaSeparatedStringToAuthorityList(""));            // 验证            Authentication auth = authenticationManager.authenticate(authRequest);            SecurityContextHolder.getContext().setAuthentication(auth);            bean.setReturnCode(1);        } catch (AuthenticationException e) {               bean.setReturnCode(0);            bean.setReturnMsg(e.getMessage());        }         return bean;    }

Angular2登录

在合适的位置编写登录函数,提交一个http请求即可。

auth(userName: string, password: string): void {    let that = this;    this.logger.info('[auth guard] start loging... userName:' + userName + ', password:' + password);    //这里通过制定headers,避免数据以json格式提交    this.headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });    //通过springsecurity的csrf保护    this.headers.append(document.getElementsByName('_csrf_header')[0].getAttribute('content'), document.getElementsByName('_csrf')[0].getAttribute('content'));    //登录过程    this.http.post(this.appStorageService.getCtx() + '/doLogin', 'userName=' + userName + '&password=' + password, { headers: this.headers }).subscribe(function (res) {      that.logger.info('[auth guard] login result');      that.logger.info(res.toString());    })  }

以上就是SpringSecurity端和Angular2端的登录改造基础步骤。下面改造Angular2的路由,使其带有用户权限验证判断功能。

Angular2路由改造

Angular2/core 包中有一个CanActivate 接口可应用于路由中,判断路由是否可激活。我们设置一个SessionStorage存储用户的登录信息即可,若无登录信息则说明用户未登陆过,若有信息则说明用户登录过。这里亦可以进一步改造后端,使用Token形式存储,更为安全。

步骤1:创建验证服务,继承CanActivate接口

在这里实现登录权限判断,与登录方法。(这里有一些我的自定义服务,缓存,日志神马的代码就不贴了)

import { Injectable } from '@angular/core';import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';import { RoutingService } from './routing.service';import { LogService } from './log.service';import { AppStorageService } from './app-storage.service';import { Bean } from '../bean/bean';import { Http, Headers } from '@angular/http';@Injectable()export class AuthGuardService implements CanActivate {  headers: Headers;  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {    if (this.appStorageService.getLoginFlag()) {      this.logger.debug('[auth guard] auth success. username:'+this.appStorageService.getUserName());      return true;    } else {      this.logger.debug('[auth guard] auth fail.')      this.routingService.toLogin();      return false;    }  }  constructor(    private http: Http,    private logger: LogService,    private routingService: RoutingService,    private appStorageService: AppStorageService  ) {  }  auth(userName: string, password: string): void {    let that = this;    this.logger.info('[auth guard] start loging... userName:' + userName + ', password:' + password);    this.headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });    this.headers.append(document.getElementsByName('_csrf_header')[0].getAttribute('content'), document.getElementsByName('_csrf')[0].getAttribute('content'));    this.http.post(this.appStorageService.getCtx() + '/doLogin', 'userName=' + userName + '&password=' + password, { headers: this.headers }).subscribe(function (res) {      that.logger.info('[auth guard] login result');      that.logger.info(res.toString());    })  }}

步骤2:增加退出代码

调用接口退出后端SpringSecurity的登录状态,清除Angular2内SessionStorage的登录信息即可。其中SpringSecurity登出是必要步骤,否则页面上是退出了,但是实际上调用后端api接口仍然是有权限的。

代码如下

  doLogout() {    let that = this;    if (!that.appStorageService.getLoginFlag()) {      that.layerService.toast('您未登录');    } else {      this.layerService.confirm('确认退出吗?', {        btns: ['退出', '取消'],        onConfirm: function () {          that.apiService.doLogout().then(function () {            that.appStorageService.setLoginFlag(false);            that.appStorageService.setUserName('');            that.layerService.toast('登出成功');          }).catch(err => that.layerService.toast(err));        }      })    }  }

步骤3:改造路由

在routes数组中为需要验证权限的路径添加canActivate接口。

import { NgModule, OnInit } from '@angular/core';import { RouterModule, Routes } from '@angular/router';import { AuthGuardService } from '../services/auth-guard.service';import { PublicComponent } from '../public.component';import { PrivateComponent } from '../private.component';const routes: Routes = [    { path: '/spa-view/public', component: PublicComponent},    { path: '/spa-view/private', component: PrivateComponent, canActivate: [AuthGuardService] },]@NgModule({    imports: [RouterModule.forRoot(routes)],    exports: [RouterModule]})export class AppRoutingModule {}
0 0
原创粉丝点击