日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 安全 认证和授权,Java安全之认证与授权

發布時間:2025/3/15 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 安全 认证和授权,Java安全之认证与授权 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java平臺提供的認證與授權服務(Java Authentication and Authorization Service (JAAS)),能夠控制代碼對敏感或關鍵資源的訪問,例如文件系統,網絡服務,系統屬性訪問等,加強代碼的安全性。主要包含認證與授權兩部分,認證的目的在于可靠安全地確定當前是誰在執行代碼,代碼可以是一個應用,applet,bean,servlet;授權的目的在于確定了當前執行代碼的用戶有什么權限,資源是否可以進行訪問。雖然JAAS表面上分為了兩大部分,而實際上兩者是密不可分的,下面看一段代碼:

public class App {

public static void main(String[] args) {

System.out.println(System.getProperty("java.home"));

}

}

非常簡單只是輸出java.home系統屬性,現在肯定是沒有任何問題,屬性會能正常輸出。把上述代碼改為如下后:

public class App {

public static void main(String[] args) {

//安裝安全管理器

System.setSecurityManager(new SecurityManager());

System.out.println(System.getProperty("java.home"));

}

}

拋出了如下異常:java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.home" "read"),異常提示沒有對java.home的讀取權限,系統屬性也是一種資源,與文件訪問類似;默認情況下對于普通Java應用是沒有安裝安全管理器,在手動安裝安全管理器后,如果沒有為應用授權則沒有任何權限,所以應用無法訪問java.home系統屬性。

授權的方式是為安全管理器綁定一個授權策略文件。由于我是在eclipse Java工程中直接運行main方法,所以就在工程根目錄下新建一個demo.policy文件,文件內容如下:

grant {

permission java.util.PropertyPermission "java.home", "read";

};

一、在運行程序的時候加入-Djava.security.policy=demo.policy虛擬機啟動參數;

二、執行System.setProperty("java.security.policy", "demo.policy");其實兩者的效果一樣,都是在設置系統屬性,其中demo.policy是路徑,這里為了簡單指定的是相對路徑,絕對路徑當然也沒問題。再次運行程序不再拋出異常,說明程序擁有了對java.home系統屬性的讀取權限。在Java中權限有很多,具體可參考:http://docs.oracle.com/javase/7/docs/technotes/guides/security/spec/security-spec.doc3.html#17001

在上述過程中雖然完成了授權,但授權的針對性不強,在程序綁定了該policy文件后,無論是哪個用戶執行都將擁有java.home系統屬性的讀權限,現在我們希望做更加細粒度的權限控制,這里需要用到認證服務了。

認證服務有點“麻煩”,一般情況下主要都涉及到了LoginContext,LoginModule,CallbackHandler,Principal,后三者還需要開發者自己實現。這里先解釋一下這幾個類的作用:

LoginContext:認證核心類,也是入口類,用于觸發登錄認證,具體的登錄模塊由構造方法name參數指定

LoginModule:登錄模塊,封裝具體的登錄認證邏輯,如果認證失敗則拋出異常,成為則向Subject中添加一個Principal

CallbackHandler:回調處理器,用于搜集認證信息

Principal:代表程序用戶的某一身份,與其密切相關的為Subject,用于代表程序用戶,而一個用戶可以多種身份,授權時可以針對某用戶的多個身份分別授權

下面看一個認證例子:

package com.xtayfjpk.security.jaas.demo;

import javax.security.auth.login.LoginContext;

import javax.security.auth.login.LoginException;

public class App {

public static void main(String[] args) {

System.setProperty("java.security.auth.login.config", "demo.config");

System.setProperty("java.security.policy", "demo.policy");

System.setSecurityManager(new SecurityManager());

try {

//創建登錄上下文

LoginContext context = new LoginContext("demo", new DemoCallbackHander());

//進行登錄,登錄不成功則系統退出

context.login();

} catch (LoginException le) {

System.err.println("Cannot create LoginContext. " + le.getMessage());

System.exit(-1);

} catch (SecurityException se) {

System.err.println("Cannot create LoginContext. " + se.getMessage());

System.exit(-1);

}

//訪問資源

System.out.println(System.getProperty("java.home"));

}

}

package com.xtayfjpk.security.jaas.demo;

import java.io.IOException;

import java.security.Principal;

import java.util.Iterator;

import java.util.Map;

import javax.security.auth.Subject;

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.NameCallback;

import javax.security.auth.callback.PasswordCallback;

import javax.security.auth.callback.UnsupportedCallbackException;

import javax.security.auth.login.FailedLoginException;

import javax.security.auth.login.LoginException;

import javax.security.auth.spi.LoginModule;

public class DemoLoginModule implements LoginModule {

private Subject subject;

private CallbackHandler callbackHandler;

private boolean success = false;

private String user;

private String password;

@Override

public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {

this.subject = subject;

this.callbackHandler = callbackHandler;

}

@Override

public boolean login() throws LoginException {

NameCallback nameCallback = new NameCallback("請輸入用戶名");

PasswordCallback passwordCallback = new PasswordCallback("請輸入密碼", false);

Callback[] callbacks = new Callback[]{nameCallback, passwordCallback};

try {

//執行回調,回調過程中獲取用戶名與密碼

callbackHandler.handle(callbacks);

//得到用戶名與密碼

user = nameCallback.getName();

password = new String(passwordCallback.getPassword());

} catch (IOException | UnsupportedCallbackException e) {

success = false;

throw new FailedLoginException("用戶名或密碼獲取失敗");

}

//為簡單起見認證條件寫死

if(user.length()>3 && password.length()>3) {

success = true;//認證成功

}

return true;

}

@Override

public boolean commit() throws LoginException {

if(!success) {

return false;

} else {

//如果認證成功則得subject中添加一個Principal對象

//這樣某身份用戶就認證通過并登錄了該應用,即表明了誰在執行該程序

this.subject.getPrincipals().add(new DemoPrincipal(user));

return true;

}

}

@Override

public boolean abort() throws LoginException {

logout();

return true;

}

@Override

public boolean logout() throws LoginException {

//退出時將相應的Principal對象從subject中移除

Iterator iter = subject.getPrincipals().iterator();

while(iter.hasNext()) {

Principal principal = iter.next();

if(principal instanceof DemoPrincipal) {

if(principal.getName().equals(user)) {

iter.remove();

break;

}

}

}

return true;

}

}

package com.xtayfjpk.security.jaas.demo;

import java.io.IOException;

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.NameCallback;

import javax.security.auth.callback.PasswordCallback;

import javax.security.auth.callback.UnsupportedCallbackException;

public class DemoCallbackHander implements CallbackHandler {

@Override

public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

NameCallback nameCallback = (NameCallback) callbacks[0];

PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];

//設置用戶名與密碼

nameCallback.setName(getUserFromSomeWhere());

passwordCallback.setPassword(getPasswordFromSomeWhere().toCharArray());

}

//為簡單起見用戶名與密碼寫死直接返回,真實情況可以由用戶輸入等具體獲取

public String getUserFromSomeWhere() {

return "zhangsan";

}

public String getPasswordFromSomeWhere() {

return "zhangsan";

}

}

package com.xtayfjpk.security.jaas.demo;

import java.security.Principal;

public class DemoPrincipal implements Principal {

private String name;

public DemoPrincipal(String name) {

this.name = name;

}

@Override

public String getName() {

return this.name;

}

}

使用認證服務時,需要綁定一個認證配置文件,在例子中通過System.setProperty("java.security.auth.login.config", "demo.config");實現,當然也可以設置虛擬屬性-Djava.security.auth.login.config=demo.config實現。配置文件內容如下:

前面說到認證與授權密不可分,這里就可以說明,在創建LoginContext對象時就需要有createLoginContext.demo的認證權限,demo就是認證配置文件中的配置名稱,該名稱在構造LoginContext對象時指定。由于在DemoLoginModule中修改了Subject的principals集合,還需要有modifyPrincipals認證權限,所以授權策略文件內容變為:

grant {

permission javax.security.auth.AuthPermission "createLoginContext.demo";

permission javax.security.auth.AuthPermission "modifyPrincipals";

permission java.util.PropertyPermission "java.home", "read";

};

再次運行程序,java.home系統屬性正常輸出,但此時我們還是沒有針對某特定用戶身份進行授權,這個就需要在授權文件中配置Principal,現在將授權文件改寫為:

grant principal com.xtayfjpk.security.jaas.demo.DemoPrincipal "zhangsan"{

permission java.util.PropertyPermission "java.home", "read";

};

grant {

permission javax.security.auth.AuthPermission "createLoginContext.demo";

permission javax.security.auth.AuthPermission "modifyPrincipals";

permission javax.security.auth.AuthPermission "doAsPrivileged";

};

這就意味著只有以名為zhangsan的DemoPrincipal登錄應用才會擁有java.home系統屬性的讀權限,此時讀取java.home的代碼需要做一定的修改,如下:

Subject subject = context.getSubject();

//該方法調用需要"doAsPrivileged"權限

Subject.doAsPrivileged(subject, new PrivilegedAction() {

@Override

public Object run() {

System.out.println(System.getProperty("java.home"));

return null;

}

}, null);

因為在Subject中才有Principal信息,這樣就可以針對每一種用戶身份制定一套權限方案。

------------------ END ---------------------

及時獲取更多精彩文章,請掃碼關注如下公眾號《Java精講》:

總結

以上是生活随笔為你收集整理的java 安全 认证和授权,Java安全之认证与授权的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。