CAS單點登錄(三)——多種認證方式


CAS單點登錄(三)——多種認證方式

https://blog.csdn.net/Anumbrella/article/details/81149249

今天我們講解一下CAS的多種認證方式,在上一篇文章中我們講解了CAS基礎服務的搭建,完成了CAS認證服務中心的簡單部署,如果忘記了話,可以先去復習一下——CAS單點登錄(二)——搭建基礎服務。

CAS認證方式有多種,我們可以根據自己的需求來實現。在前一篇文章中搭建服務中我們其實就把CAS的JDBC認證方式講解了,在讀取用戶名我們可以指定為從數據庫的表中讀取數據。

一、JDBC認證
我們還是接着上次的代碼進行講解,你可以先下載先前的代碼——Chapter1。上次在CAS基本服務搭建的代碼中,我們只是簡單的使用了一下,今天我們將完善更多的配置。

在前面我們設計了一個user表,表的字段為:

字段名 字段類型 備注
id bigint ID
username varchar 用戶名
password varchar 用戶密碼
expired bigint 過期字段,1為過期,需修改密碼
disabled bigint 不可用字段,1為不可用,禁用
常用單向加密算法:MD5、SHA、HMAC。

一般我們常用的加密算法就這幾種。在JDBC認證中我們也可以選擇配置加密算法,加密算法一般為上面的三種,MD5、SHA、HMAC,加密類型為NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2這幾種,我們在配置文件中選擇加密類型,指定加密算法。

 

前面配置不變指定JDBC配置,后面的配置為密碼加密策略,配置如下:

##
# JDBC配置
#
#查詢賬號密碼SQL,必須包含密碼字段
cas.authn.jdbc.query[0].sql=select * from user where username=?

#指定上面的SQL查詢字段名(必須)
cas.authn.jdbc.query[0].fieldPassword=password

#指定過期字段,1為過期,若過期不可用
cas.authn.jdbc.query[0].fieldExpired=expired

#為不可用字段段,1為不可用,需要修改密碼
cas.authn.jdbc.query[0].fieldDisabled=disabled

#數據庫連接
cas.authn.jdbc.query[0].url=jdbc:mysql://127.0.0.1:3306/cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false

#數據庫dialect配置
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect

#數據庫用戶名
cas.authn.jdbc.query[0].user=root

#數據庫用戶密碼
cas.authn.jdbc.query[0].password=123

#數據庫事務自動提交
cas.authn.jdbc.query[0].autocommit=false

#數據庫驅動
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver

#超時配置
cas.authn.jdbc.query[0].idleTimeout=5000

#默認加密策略,通過encodingAlgorithm來指定算法,默認NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
# 字符類型
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
# 加密鹽
#cas.authn.jdbc.query[0].passwordEncoder.secret=
# 加密字符長度
#cas.authn.jdbc.query[0].passwordEncoder.strength=16
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
然后我們啟動應用。當我們運行起CAS,輸入原來的用戶名和密碼——anumbrella/anumbrella,並不能登錄,因為我們更改密碼驗證為MD5加密模式了。將anumbrella使用md5加密后,填入數據庫,再次登錄,可以發現登錄成功。由此驗證我們加密成功!

接着我們再新增用戶test、test2、test3,密碼分別為用戶名md5加密,而test2的expired,test3的disabled都為1。如下:


因此當我們登錄test2和test3用戶時,將會有需要更改密碼和禁用提示。

 

 

除此之外如果我們要自定義加密類型,就需要實現org.springframework.security.crypto.password.PasswordEncoder接口,並且把類名配置在passwordEncoder.type。

這里配置為自定義加密,新建類MyPasswordEncoder。

package net.anumbrella.sso;

import org.springframework.security.crypto.password.PasswordEncoder;

/**
* @author anumbrella
*/
public class MyPasswordEncoder implements PasswordEncoder {

@Override
public String encode(CharSequence charSequence) {
// charSequence為輸入的用戶密碼
return charSequence.toString();
}

@Override
public boolean matches(CharSequence charSequence, String str) {
// 當encode方法返回不為null時,matches方法才會調用,charSequence為encode返回的字符串
// str字符串為數據庫中密碼字段返回的值
String encodeStr = charSequence.toString() + "aa";
if (encodeStr.equals(str)) {
return true;
}
return false;
}
}
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
更改配置為:

cas.authn.jdbc.query[0].passwordEncoder.type=net.anumbrella.sso.MyPasswordEncoder
1
更改anumbrella用戶密碼為11aa,啟動應用,根據加密算法只要我們登錄輸入密碼11即可驗證成功。

如果要密碼無加密,調整passwordEncoder.type=NONE。
如果要加密策略為SHA,調整passwordEncoder.encodingAlgorithm=SHA。

到此JDBC的認證方式我們就講解完畢了,關於更多的使用參考文檔:

密碼加密配置:

https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties-Common.html#password-encoding

二、白名單(Whitelist)認證
CAS同時也支持白名單認證方式,主要是File和JSON格式。

File形式:

添加依賴包:

<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-generic</artifactId>
<version>${cas.version}</version>
</dependency>
1
2
3
4
5
6
在配置文件中添加如下配置:

##
# 白名單——file配置
#
cas.authn.file.separator=::
cas.authn.file.filename=file:///Users/anumbrella/file
cas.authn.file.name=
1
2
3
4
5
6
在/Users/anumbrella目錄下,新建file文件,內容如下:

anumbrella::anumbrella
test::test
test2::test2
1
2
3
該文件配置對應的就是用戶名和密碼,重啟CAS,可以發現配置生效了。

同樣的如果我們要配置密碼加密,與上面JDBC配置加密一樣,更改配置文件如下:

#默認加密策略,通過encodingAlgorithm來指定算法,默認NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.file.passwordEncoder.type=DEFAULT
# 字符類型
cas.authn.file.passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.file.passwordEncoder.encodingAlgorithm=MD5
1
2
3
4
5
6
7
其他都完全一致,只是更改配置文件前部分更改為對應的認證類型的即可。

JSON形式:

與File相似,一樣添加依賴包:

<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-generic</artifactId>
<version>${cas.version}</version>
</dependency>
1
2
3
4
5
在配置文件中添加如下配置:

##
# 白名單——json配置
#
cas.authn.json.location=file:///Users/anumbrella/file.json
cas.authn.json.name=
1
2
3
4
5
在/Users/anumbrella目錄下,新建file.json文件,內容如下:

{
"@class" : "java.util.LinkedHashMap",
"anumbrella" : {
"@class" : "org.apereo.cas.adaptors.generic.CasUserAccount",
"password" : "anumbrella",
"attributes" : {
"@class" : "java.util.LinkedHashMap",
"firstName" : "shu",
"lastName" : "yun"
},
"status" : "OK",
"expirationDate" : "2018-10-19"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
用戶名和密碼仍然為anumbrella/anumbrella。

同樣的如果我們要配置密碼加密,更改配置文件如下:

#默認加密策略,通過encodingAlgorithm來指定算法,默認NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.json.passwordEncoder.type=DEFAULT
# 字符類型
cas.authn.json.passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.json.passwordEncoder.encodingAlgorithm=MD5
1
2
3
4
5
6
7
三、黑名單(Blacklist)認證
在CAS中黑名單的配置就比較簡單,配置如下:

##
# 黑名單配置
#
cas.authn.reject.users=test,anumbrella
cas.authn.reject.name=
1
2
3
4
5
當不在黑名單中的用戶,就會全部接受,用戶甚至亂輸入密碼都可實現登錄。

同樣的如果我們要配置密碼加密,更改配置文件如下:

#默認加密策略,通過encodingAlgorithm來指定算法,默認NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.reject.passwordEncoder.type=DEFAULT
# 字符類型
cas.authn.reject.passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.reject.passwordEncoder.encodingAlgorithm=MD5
1
2
3
4
5
6
7
四、Shiro認證
我們知道Shiro是個一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。通過使用Shiro可以快速搭建一套角色、權限控制的流程,因此Shiro使用的機會還是很大的。

添加依賴包如下:

<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-shiro-authentication</artifactId>
<version>${cas.version}</version>
</dependency>
1
2
3
4
5
6
在配置文件添加如下:

##
# Shiro配置
#
#允許登錄的用戶,必須要有以下權限,否則拒絕,多個逗號隔開
cas.authn.shiro.requiredPermissions=staff
#允許登錄的用戶,必須要有以下角色,否則拒絕,多個逗號隔開
cas.authn.shiro.requiredRoles=admin
#shir配置文件位置
cas.authn.shiro.location=classpath:shiro.ini
#shiro name 唯一
cas.authn.shiro.name=cas-shiro
1
2
3
4
5
6
7
8
9
10
11
在resources下新建shiro.ini文件,配置如下:

[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager

[users]
anumbrella = 123, admin
test = test, developer

[roles]
admin = system,admin,staff,superuser:*
developer = commit:*
1
2
3
4
5
6
7
8
9
10
11
這里的shiro.ini文件,主要是看shiro的配置情況,可以根據具體的需求進行更改。

重啟CAS服務,根據我們的配置可以發現anumbrella用戶可以登錄,test用戶登錄失敗,沒有相應的權限。

同樣的如果我們要配置密碼加密,更改配置文件如下:

#默認加密策略,通過encodingAlgorithm來指定算法,默認NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.shiro.passwordEncoder.type=DEFAULT
# 字符類型
cas.authn.shiro.passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.shiro.passwordEncoder.encodingAlgorithm=MD5
1
2
3
4
5
6
7
五、Rest認證
這里的Rest認證就是指通過數據接口對用戶進行認證,通過發起一個POST請求來進行認證。
當用戶點擊登錄后,CAS會發送POST請求到在請求頭中包含一個Authorization認證,里面的值為Basic XYZ,而這個XYZ就是通過Base64編碼后的用戶信息。

比如:
若輸入用戶名密碼為:anumbrella/123

那么請求頭包括:
authorization=Basic Base64(anumbrella:123)

同樣的添加依賴包:

<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-rest-authentication</artifactId>
<version>${cas.version}</version>
</dependency>
1
2
3
4
5
然后再配置文件中添加配置:

##
# Rest配置
#
cas.authn.rest.uri=http://localhost:8088/login
cas.authn.rest.name=
1
2
3
4
5
如果登錄成功響應200,返回響應中包含id和attributes字段,如下:

{"@class":"org.apereo.cas.authentication.principal.SimplePrincipal","id":"casuser","attributes":{}}
1
如果失敗,返回的結果可能如下:

 

返回狀態碼:403用戶不可用;404賬號不存在;423賬戶被鎖定;412過期;428密碼需要更改;其他登錄失敗

我們新建一個Spring Boot服務,用來模擬Rest請求的地址的服務,新建SysUser類,用來定義返回約束的json。

public class SysUser {

@JsonProperty("id")
@NotNull
private String username;

@JsonProperty("@class")
//需要返回實現org.apereo.cas.authentication.principal.Principal的類名接口
private String clazz = "org.apereo.cas.authentication.principal.SimplePrincipal";


@JsonProperty("attributes")
private Map<String, Object> attributes = new HashMap<String, Object>();

@JsonIgnore
@NotNull
private String password;

@JsonIgnore
//用戶是否不可用
private boolean disable = false;


@JsonIgnore
//用戶是否過期
private boolean expired = false;

@JsonIgnore
//是否鎖定
private boolean locked = false;

public boolean isLocked() {
return locked;
}

public SysUser setLocked(boolean locked) {
this.locked = locked;
return this;
}

public boolean isDisable() {
return disable;
}

public SysUser setDisable(boolean disable) {
this.disable = disable;
return this;
}

public boolean isExpired() {
return expired;
}

public SysUser setExpired(boolean expired) {
this.expired = expired;
return this;
}

public String getPassword() {
return password;
}

public SysUser setPassword(String password) {
this.password = password;
return this;
}

public String getUsername() {
return username;
}

public SysUser setUsername(String username) {
this.username = username;
return this;
}

public String getClazz() {
return clazz;
}

public Map<String, Object> getAttributes() {
return attributes;
}

public SysUser setAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
return this;
}

@JsonIgnore
public SysUser addAttribute(String key, Object val) {
getAttributes().put(key, val);
return this;
}
}
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
然后再Controller層里,定義路徑/login的POST方法。

@RestController
public class RestAuthController {

private static final Logger LOGGER = LoggerFactory.getLogger(RestAuthController.class);

/**
* 1. cas 服務端會通過post請求,並且把用戶信息以"用戶名:密碼"進行Base64編碼放在authorization請求頭中
* 2. 返回200狀態碼並且格式為{"@class":"org.apereo.cas.authentication.principal.SimplePrincipal","id":"casuser","attributes":{}} 是成功的
* 2. 返回狀態碼403用戶不可用;404賬號不存在;423賬戶被鎖定;428過期;其他登錄失敗
*
* @param httpHeaders
* @return
*/
@PostMapping("/login")
public Object login(@RequestHeader HttpHeaders httpHeaders) {
LOGGER.info("Rest api login.");
LOGGER.debug("request headers: {}", httpHeaders);
SysUser user = null;
try {
UserTemp userTemp = obtainUserFormHeader(httpHeaders);
//嘗試查找用戶庫是否存在
user = new SysUser();
user.setUsername("anumbrella");
user.setPassword("123");
if (user != null) {
if (!user.getPassword().equals(userTemp.password)) {
//密碼不匹配
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}
if (user.isDisable()) {
//禁用 403
return new ResponseEntity(HttpStatus.FORBIDDEN);
}
if (user.isLocked()) {
//鎖定 423
return new ResponseEntity(HttpStatus.LOCKED);
}
if (user.isExpired()) {
//過期 428
return new ResponseEntity(HttpStatus.PRECONDITION_REQUIRED);
}
} else {
//不存在 404
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
} catch (UnsupportedEncodingException e) {
LOGGER.error("", e);
new ResponseEntity(HttpStatus.BAD_REQUEST);
}
LOGGER.info("[{}] login is ok", user.getUsername());
//成功返回json
return user;
}

/**
* 根據請求頭獲取用戶名及密碼
*
* @param httpHeaders
* @return
* @throws UnsupportedEncodingException
*/
private UserTemp obtainUserFormHeader(HttpHeaders httpHeaders) throws UnsupportedEncodingException {
/**
*
* This allows the CAS server to reach to a remote REST endpoint via a POST for verification of credentials.
* Credentials are passed via an Authorization header whose value is Basic XYZ where XYZ is a Base64 encoded version of the credentials.
*/
//當請求過來時,會通過把用戶信息放在請求頭authorization中,並且通過Basic認證方式加密
String authorization = httpHeaders.getFirst("authorization");//將得到 Basic Base64(用戶名:密碼)
String baseCredentials = authorization.split(" ")[1];
String usernamePassword = Base64Utils.decoder(baseCredentials);//用戶名:密碼
LOGGER.debug("login user: {}", usernamePassword);
String credentials[] = usernamePassword.split(":");
return new UserTemp(credentials[0], credentials[1]);
}

/**
* 解析請求過來的用戶
*/
private class UserTemp {
private String username;
private String password;

public UserTemp(String username, String password) {
this.username = username;
this.password = password;
}
}
}
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
81
82
83
84
85
86
87
88
89
我們使用PostMan模擬CAS服務登錄,向http://localhost:8088/login發起一個POST請求,請求中包含用戶名和密碼的認證信息,在Rest服務中,我將用戶名和密碼寫死了,定為anumbrella/123,當然這里可以按具體需求連接數據庫來實現。如下:

 

最后返回我們期望的結果,現在我們更改CAS配置rest地址為http://localhost:8088/login,重啟服務,然后輸入密碼登錄測試。

 

可以發現登錄成功,我們實現了Rest服務認證。

同樣的,這里我們密碼沒有進行加密配置。如果我們要配置密碼加密,更改配置文件如下:

#默認加密策略,通過encodingAlgorithm來指定算法,默認NONE不加密
# NONE|DEFAULT|STANDARD|BCRYPT|SCRYPT|PBKDF2
cas.authn.rest.passwordEncoder.type=DEFAULT
# 字符類型
cas.authn.rest.passwordEncoder.characterEncoding=UTF-8
# 加密算法
cas.authn.rest.passwordEncoder.encodingAlgorithm=MD5
1
2
3
4
5
6
7
到這里CAS的多種認證方式就講完了,當然CAS的認證還有很多種,可以去查看官方的文檔——配置文檔。

代碼實例:Chapter2

參考
https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties.html
CAS單點登錄-自定義認證之Shiro、Rest(六)
————————————————
版權聲明:本文為CSDN博主「Anumbrella」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/Anumbrella/article/details/81149249


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM