一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - SpringSecurity登錄使用JSON格式數(shù)據(jù)的方法

SpringSecurity登錄使用JSON格式數(shù)據(jù)的方法

2021-07-15 14:48江南一點(diǎn)雨 Java教程

這篇文章主要介紹了SpringSecurity登錄使用JSON格式數(shù)據(jù)的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在使用springsecurity中,大伙都知道默認(rèn)的登錄數(shù)據(jù)是通過key/value的形式來傳遞的,默認(rèn)情況下不支持json格式的登錄數(shù)據(jù),如果有這種需求,就需要自己來解決,本文主要和小伙伴來聊聊這個話題。

基本登錄方案

在說如何使用json登錄之前,我們還是先來看看基本的登錄吧,本文為了簡單,springsecurity在使用中就不連接數(shù)據(jù)庫了,直接在內(nèi)存中配置用戶名和密碼,具體操作步驟如下:

創(chuàng)建spring boot工程

首先創(chuàng)建springboot工程,添加springsecurity依賴,如下:

?
1
2
3
4
5
6
7
8
<dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter-security</artifactid>
</dependency>
<dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter-web</artifactid>
</dependency>

添加security配置

創(chuàng)建securityconfig,完成springsecurity的配置,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
@configuration
public class securityconfig extends websecurityconfigureradapter {
  @bean
  passwordencoder passwordencoder() {
    return new bcryptpasswordencoder();
  }
  @override
  protected void configure(authenticationmanagerbuilder auth) throws exception {
    auth.inmemoryauthentication().withuser("zhangsan").password("$2a$10$2o4ewlrrfpebotfdotc0f.rpumk.3q3kvbhrx7xxkumlbgjoobs8q").roles("user");
  }
 
  @override
  public void configure(websecurity web) throws exception {
  }
 
  @override
  protected void configure(httpsecurity http) throws exception {
    http.authorizerequests()
        .anyrequest().authenticated()
        .and()
        .formlogin()
        .loginprocessingurl("/dologin")
        .successhandler(new authenticationsuccesshandler() {
          @override
          public void onauthenticationsuccess(httpservletrequest req, httpservletresponse resp, authentication authentication) throws ioexception, servletexception {
            respbean ok = respbean.ok("登錄成功!",authentication.getprincipal());
            resp.setcontenttype("application/json;charset=utf-8");
            printwriter out = resp.getwriter();
            out.write(new objectmapper().writevalueasstring(ok));
            out.flush();
            out.close();
          }
        })
        .failurehandler(new authenticationfailurehandler() {
          @override
          public void onauthenticationfailure(httpservletrequest req, httpservletresponse resp, authenticationexception e) throws ioexception, servletexception {
            respbean error = respbean.error("登錄失敗");
            resp.setcontenttype("application/json;charset=utf-8");
            printwriter out = resp.getwriter();
            out.write(new objectmapper().writevalueasstring(error));
            out.flush();
            out.close();
          }
        })
        .loginpage("/login")
        .permitall()
        .and()
        .logout()
        .logouturl("/logout")
        .logoutsuccesshandler(new logoutsuccesshandler() {
          @override
          public void onlogoutsuccess(httpservletrequest req, httpservletresponse resp, authentication authentication) throws ioexception, servletexception {
            respbean ok = respbean.ok("注銷成功!");
            resp.setcontenttype("application/json;charset=utf-8");
            printwriter out = resp.getwriter();
            out.write(new objectmapper().writevalueasstring(ok));
            out.flush();
            out.close();
          }
        })
        .permitall()
        .and()
        .csrf()
        .disable()
        .exceptionhandling()
        .accessdeniedhandler(new accessdeniedhandler() {
          @override
          public void handle(httpservletrequest req, httpservletresponse resp, accessdeniedexception e) throws ioexception, servletexception {
            respbean error = respbean.error("權(quán)限不足,訪問失敗");
            resp.setstatus(403);
            resp.setcontenttype("application/json;charset=utf-8");
            printwriter out = resp.getwriter();
            out.write(new objectmapper().writevalueasstring(error));
            out.flush();
            out.close();
          }
        });
 
  }
}

這里的配置雖然有點(diǎn)長,但是很基礎(chǔ),配置含義也比較清晰,首先提供bcryptpasswordencoder作為passwordencoder,可以實(shí)現(xiàn)對密碼的自動加密加鹽,非常方便,然后提供了一個名為zhangsan的用戶,密碼是123,角色是user,最后配置登錄邏輯,所有的請求都需要登錄后才能訪問,登錄接口是/dologin,用戶名的key是username,密碼的key是password,同時配置登錄成功、登錄失敗以及注銷成功、權(quán)限不足時都給用戶返回json提示,另外,這里雖然配置了登錄頁面為/login,實(shí)際上這不是一個頁面,而是一段json,在logincontroller中提供該接口,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
@restcontroller
@responsebody
public class logincontroller {
  @getmapping("/login")
  public respbean login() {
    return respbean.error("尚未登錄,請登錄");
  }
  @getmapping("/hello")
  public string hello() {
    return "hello";
  }
}

這里/login只是一個json提示,而不是頁面, /hello則是一個測試接口。

ok,做完上述步驟就可以開始測試了,運(yùn)行springboot項(xiàng)目,訪問/hello接口,結(jié)果如下:

SpringSecurity登錄使用JSON格式數(shù)據(jù)的方法

此時先調(diào)用登錄接口進(jìn)行登錄,如下:

SpringSecurity登錄使用JSON格式數(shù)據(jù)的方法

登錄成功后,再去訪問/hello接口就可以成功訪問了。

使用json登錄

上面演示的是一種原始的登錄方案,如果想將用戶名密碼通過json的方式進(jìn)行傳遞,則需要自定義相關(guān)過濾器,通過分析源碼我們發(fā)現(xiàn),默認(rèn)的用戶名密碼提取在usernamepasswordauthenticationfilter過濾器中,部分源碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class usernamepasswordauthenticationfilter extends
    abstractauthenticationprocessingfilter {
  public static final string spring_security_form_username_key = "username";
  public static final string spring_security_form_password_key = "password";
 
  private string usernameparameter = spring_security_form_username_key;
  private string passwordparameter = spring_security_form_password_key;
  private boolean postonly = true;
  public usernamepasswordauthenticationfilter() {
    super(new antpathrequestmatcher("/login", "post"));
  }
 
  public authentication attemptauthentication(httpservletrequest request,
      httpservletresponse response) throws authenticationexception {
    if (postonly && !request.getmethod().equals("post")) {
      throw new authenticationserviceexception(
          "authentication method not supported: " + request.getmethod());
    }
 
    string username = obtainusername(request);
    string password = obtainpassword(request);
 
    if (username == null) {
      username = "";
    }
 
    if (password == null) {
      password = "";
    }
 
    username = username.trim();
 
    usernamepasswordauthenticationtoken authrequest = new usernamepasswordauthenticationtoken(
        username, password);
 
    // allow subclasses to set the "details" property
    setdetails(request, authrequest);
 
    return this.getauthenticationmanager().authenticate(authrequest);
  }
 
  protected string obtainpassword(httpservletrequest request) {
    return request.getparameter(passwordparameter);
  }
 
  protected string obtainusername(httpservletrequest request) {
    return request.getparameter(usernameparameter);
  }
  //...
  //...
}

從這里可以看到,默認(rèn)的用戶名/密碼提取就是通過request中的getparameter來提取的,如果想使用json傳遞用戶名密碼,只需要將這個過濾器替換掉即可,自定義過濾器如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class customauthenticationfilter extends usernamepasswordauthenticationfilter {
  @override
  public authentication attemptauthentication(httpservletrequest request, httpservletresponse response) throws authenticationexception {
    if (request.getcontenttype().equals(mediatype.application_json_utf8_value)
        || request.getcontenttype().equals(mediatype.application_json_value)) {
      objectmapper mapper = new objectmapper();
      usernamepasswordauthenticationtoken authrequest = null;
      try (inputstream is = request.getinputstream()) {
        map<string,string> authenticationbean = mapper.readvalue(is, map.class);
        authrequest = new usernamepasswordauthenticationtoken(
            authenticationbean.get("username"), authenticationbean.get("password"));
      } catch (ioexception e) {
        e.printstacktrace();
        authrequest = new usernamepasswordauthenticationtoken(
            "", "");
      } finally {
        setdetails(request, authrequest);
        return this.getauthenticationmanager().authenticate(authrequest);
      }
    }
    else {
      return super.attemptauthentication(request, response);
    }
  }
}

這里只是將用戶名/密碼的獲取方案重新修正下,改為了從json中獲取用戶名密碼,然后在securityconfig中作出如下修改:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@override
protected void configure(httpsecurity http) throws exception {
  http.authorizerequests().anyrequest().authenticated()
      .and()
      .formlogin()
      .and().csrf().disable();
  http.addfilterat(customauthenticationfilter(), usernamepasswordauthenticationfilter.class);
}
@bean
customauthenticationfilter customauthenticationfilter() throws exception {
  customauthenticationfilter filter = new customauthenticationfilter();
  filter.setauthenticationsuccesshandler(new authenticationsuccesshandler() {
    @override
    public void onauthenticationsuccess(httpservletrequest req, httpservletresponse resp, authentication authentication) throws ioexception, servletexception {
      resp.setcontenttype("application/json;charset=utf-8");
      printwriter out = resp.getwriter();
      respbean respbean = respbean.ok("登錄成功!");
      out.write(new objectmapper().writevalueasstring(respbean));
      out.flush();
      out.close();
    }
  });
  filter.setauthenticationfailurehandler(new authenticationfailurehandler() {
    @override
    public void onauthenticationfailure(httpservletrequest req, httpservletresponse resp, authenticationexception e) throws ioexception, servletexception {
      resp.setcontenttype("application/json;charset=utf-8");
      printwriter out = resp.getwriter();
      respbean respbean = respbean.error("登錄失敗!");
      out.write(new objectmapper().writevalueasstring(respbean));
      out.flush();
      out.close();
    }
  });
  filter.setauthenticationmanager(authenticationmanagerbean());
  return filter;
}

將自定義的customauthenticationfilter類加入進(jìn)來即可,接下來就可以使用json進(jìn)行登錄了,如下:

SpringSecurity登錄使用JSON格式數(shù)據(jù)的方法

好了,本文就先介紹到這里,有問題歡迎留言討論。 希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://segmentfault.com/a/1190000018157525

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产成人精品日本亚洲网址 | 四虎影院精品在线观看 | 欧美一区二区三区大片 | 四虎影视在线影院在线观看 | chinese老太grandma | 久久精品无码一区二区日韩av | xxxxxx日本处大片免费看 | 日本噜噜影院 | 久久精品国产免费播放 | 日韩免费视频播放 | 波多野结衣在线免费观看 | 三体动漫在线观看免费完整版2022 | 大胸美女被c| 色婷婷久久综合中文久久一本` | 久久亚洲伊人 | 911精品国产亚洲日本美国韩国 | xvideoscom极品肌肉警察 | 91视频国产自拍 | 亚洲第一福利视频 | 欧美成人乱弄视频 | 天天干天天色综合 | 国产午夜精品一区二区三区不卡 | 亚洲国产99在线精品一区69堂 | 亚洲午夜精品久久久久 | 亚洲日本va午夜中文字幕 | 香蕉成人国产精品免费看网站 | 18美女光胸光屁屁洗澡 | 男人的天堂日本 | 99免费看| 天天爱天天做天天爽天天躁 | 男同互操 | 免费视频网 | 国产一区二区视频在线观看 | 王淑兰与铁柱全文免费阅读 | jizz中国jizz老师水多 | 国产精品久久国产精品99盘 | 高清毛片aaaaaaaaa片 | 国产精品主播在线 | 性xxxx中国老妇506070 | 女烈受刑重口小说 | 日韩伦理在线看 |