shiro | Spring security |
---|---|
粗粒度 | 細粒度 |
功能夠用 | 功能更細更多 |
學(xué)習(xí)難度低 | 學(xué)習(xí)難度高 |
Shiro四大基石
名稱 | 意思 |
---|---|
Authentication | 身份驗證:登錄--- 噢搜體k森 |
Authorization | 授權(quán):權(quán)限判斷 ---- 噢搜銳z森 |
Cryptography | 密碼學(xué):加密 |
Session Management | 會話管理:session |
會話管理:
用戶登錄墩蔓,會把用戶名和密碼傳到后臺衡瓶,后臺會去數(shù)據(jù)庫中找有沒有這個人褐奥,如果有登錄成功往枷,會存在session中(通過HttpSession。web項目中才有展东,CS中就沒有這個類了)哥蔚。但是這里session提供了這個功能伞梯,不用在考慮有沒有HttpSession
核心類
- Subject(啥不j可特)---當(dāng)前用戶(游客/登錄用戶)如果要登錄需要令牌
- SecurityManager (C可瑞 麥泥著)---- Shiro的權(quán)限管理器【Shiro所有功能都是通過他】(最重要)
- Reaim(入母) ---- 去拿到登錄等的值【拿數(shù)據(jù)、獲取數(shù)據(jù)】
Shiro官方有所有案例
我們現(xiàn)在用的是SpringMVC所以使用路徑判斷xue微好一點
其實兩個方式都差不多倔撞,都可以用讲仰,Controller.save()是Struts2好一點
權(quán)限表關(guān)系(重)
- 用戶----角色 --- 多對多 【一個人有多個角色,一個角色有多個人】
- 角色-----權(quán)限----多對多 【一個角色有多個功能痪蝇,一個功能對應(yīng)多個角色】
速成案例
1.新建maven項目
2.導(dǎo)jar包
<!--shiro支持包-->
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!--日志支持包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--測試包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
3.導(dǎo)入shiro.ini 文件
一鄙陡、獲取SecurityManager對象
1.獲取Shiro.ini文件
2.從工廠中獲取到SecurityManager對象
二、把SecurityManager對象設(shè)置到上下文中
三躏啰、獲取到當(dāng)前用戶(如果沒有登錄就是游客)
1.判斷短是否登錄----isAuthenicated()
2.如果沒有登錄就讓他登錄
①登錄需要令牌----UsernamePasswordToken
②根據(jù)令牌實現(xiàn)登錄
3,注銷登錄 ---- login()
4.try一下 如果輸錯報出錯誤
①Unknown(未知的)Account(賬號)Exception---賬戶錯誤
②Incorrect(錯誤的)Credentials(憑證)Exception--密碼錯誤
③AuthenicationException----最大的錯誤(神秘錯誤)
hasRole() ------ 判斷是否是存在角色(返回true趁矾、false)角色判斷
isPermitted() ------ 判斷是否有該權(quán)限(返回true/false)權(quán)限判斷
定義一個自己的Realm 繼承extends AuthorizingRealm
繼承完就要實現(xiàn)兩個方法 一個授權(quán)一個登陸
完成版
public class ShiroTest {
@Test
public void ShiroTest() throws Exception{
//拿到SecurityManager核心對象
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
//把SecurityManager對象放到當(dāng)前的上下文中
SecurityUtils.setSecurityManager(securityManager);
//拿到當(dāng)前用戶
Subject subject = SecurityUtils.getSubject();
//獲得令牌 ---- 判斷
//④.如果沒有登錄,讓他登錄(需要令牌)
if(!subject.isAuthenticated()){
try {
//用戶名密碼令牌
AuthenticationToken token = new UsernamePasswordToken("root","123456");
//登錄功能
subject.login(token);
} catch (UnknownAccountException e) {//Unknown(未知)Account(賬號)Exception
e.printStackTrace();
System.out.println("用戶名錯誤给僵!");
} catch (IncorrectCredentialsException e) {//Incorrect(不正確的)Credentials(憑證;證書)Exception
e.printStackTrace();
System.out.println("密碼錯誤毫捣!");
}catch (AuthenticationException e){
e.printStackTrace();
System.out.println("出現(xiàn)一個神迷的錯誤!5奂省B!");
}
}
//對于角色的判斷
System.out.println("是否是admin角色:"+subject.hasRole("admin"));
System.out.println("是否是it角色:"+subject.hasRole("it"));
//判斷相應(yīng)的權(quán)限
System.out.println("是否是employee:save權(quán)限:"+subject.isPermitted("employee:save"));
System.out.println("是否是employee:update權(quán)限:"+subject.isPermitted("employee:update"));
System.out.println("是否是department:save權(quán)限:"+subject.isPermitted("department:save"));
//判斷這個用戶是否登錄
System.out.println("是否登錄:" + subject.isAuthenticated());
//注銷,退出,登出
subject.logout();
System.out.println("是否登錄:" + subject.isAuthenticated());
}
}
上面都是在用Shiro.ini文件代替數(shù)據(jù)庫玩的《拙鳎現(xiàn)在開始用數(shù)據(jù)庫來操作
案例2:自定義Realm
身份認證的代碼
/**
* 自定義一個Realm
*/
public class MyRealm extends AuthorizingRealm {
//獲取到這個Realm的名稱(隨便取)
@Override
public String getName() {
return "MyRealm";
}
//進行授權(quán)的認證
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//進行登錄的認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//明顯的知道:這個authenticationToken就是UsernamePasswordtoken
//1.拿到閘門的令牌(用戶名密碼Token)--把令牌強轉(zhuǎn)成用戶名密碼令牌
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String username = token.getUsername(); //2.拿到用戶名(注:這個用戶名是傳過來的)
//3.這里根據(jù)用戶名到數(shù)據(jù)庫中去獲取密碼(如果沒有獲取到牌柄,相當(dāng)于這個用戶不存在,就返回null值)
String password = getByName(username);
if(password==null){//判斷如果password為空侧甫,那就返回空
//3.返回空就是代表用戶名不存在珊佣,shiro會自動幫你報UnknowAcctountException
return null;
}
//創(chuàng)建一個簡單的身份信息(把用戶名與密碼放進去-注:它會自動的比較獲取的密碼與你傳過來的密碼)
//4.傳的是數(shù)據(jù)庫密碼:他要把這個密碼和令牌中的密碼做比較蹋宦,如果對應(yīng)不上,就會報IncorrectCredentialsException
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,getName());
//參數(shù)(主體(一般是當(dāng)前用戶名)咒锻,密碼冷冗,realm名字)--- 除了密碼,其他都隨意寫
return authenticationInfo;
}
//模擬從數(shù)據(jù)庫中獲取信息
private String getByName(String username) {
if("admin".equals(username)){
return "123456";
}else if("guest".equals(username)){
return "abcd";
}
return null;
}
}
創(chuàng)建測試登陸代 碼
@Test
public void testMyRealm() throws Exception{
//創(chuàng)建自己定義的Realm
MyRealm myRealm = new MyRealm();
//拿到SecurityManager對象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//把Realm放到securityManager中去
securityManager.setRealm(myRealm);
//把SecurityManager放到上下文章
//把權(quán)限管理器放到相應(yīng)的環(huán)境中(我們可以在項目任何位置拿到)
SecurityUtils.setSecurityManager(securityManager);
//拿到當(dāng)前用戶(Subject就是當(dāng)前用戶,游客)
Subject currentUser = SecurityUtils.getSubject();
//判斷一下是否登錄
System.out.println(""+ currentUser.isAuthenticated());
//準(zhǔn)備登錄的令牌(準(zhǔn)備用戶名與密碼)
UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
try {
//根據(jù)令牌進行功能登錄(當(dāng)前用戶進行登錄)
currentUser.login(token);
} catch (UnknownAccountException e) {
System.out.println("這個賬號不存在!" + token.getPrincipal());
e.printStackTrace();
} catch (IncorrectCredentialsException ice) {
System.out.println("這個密碼不存在!" + token.getPrincipal());
ice.printStackTrace();
}catch (AuthenticationException e){//神秘錯誤
System.out.println("i don't k");
}
}
授權(quán)(權(quán)限功能)
就是上面自定義Realm的時候惑艇,授權(quán)沒有寫蒿辙,先搞得身份認證。現(xiàn)在回去在搞授權(quán)
密碼加密(Shiro---密碼學(xué))
簡單地說就是把看的懂得密碼改成看不懂的
知識點
1.CS/BS :
CS是qq滨巴,畫圖板等等思灌,通過軟件 --------- BS就是webqq,通過頁面展示出來的
2.粗粒度/細粒度:
粗粒度比如能不能添加用戶恭取,能不能刪除用戶泰偿。 --------細粒度就是在粗粒度能完成的的功能下還能在精細一點。功能更完美一點
??????????java育兒園里的小學(xué)生“磨陀貨”友情提供r诳濉:孽恕!
??????????請大家尊重原創(chuàng)攒发,如要轉(zhuǎn)載调塌,請注明出處:
??????????轉(zhuǎn)載自:http://www.reibang.com/p/606e67f7cd1a,謝謝;菰场羔砾!
??????????有任何疑問,歡迎加入Java交流群458443587(加群時請備注)