身份认证
身份认证分三个步骤
1)提交主题和凭据
2)进行身份认证
3)判断是通过,重新提交还是不通过
验证顺序
1)调用subject的login方法,提交主体和凭据。
2)得到对应操作的Security Manager
3)通过Sceurity Manager得到对应的Autherticator实例
4)根据配置策略查找对应的桥信息
5)通过桥信息到对应的配置处理进行身份验证
验证器
如果你想配置一个自定义的验证器
可以在配置文件中使用
[main]
...
authenticator = com.foo.bar.CustomAuthenticator
securityManager.authenticator = $authenticator
|
配置策略信息
AtLeastOneSuccessfulStrategy 如果一个验证成功,则验证结果为成功
FirstSuccessfulStrategy 只有第一个成功,才算成功
AllSuccessfulStrategy 所有的都必须成功
对应的在配置文件中的策略使用如下
shiro.ini
[main]
...
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
...
|
执行顺序
1)隐式顺序
blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm
|
按上下顺序执行
2)指定顺序
blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm
securityManager.realms = $fooRealm, $barRealm, $blahRealm
...
|
按指定的顺序执行
授权
控制谁有权限访问应用程序
授权的几个要素:权限,角色和用户。
三种权限的判断方式
1)编程
角色判断
Subject currentUser = SecurityUtils.getSubject();
if
(currentUser.hasRole(
"administrator"
)) {
//show the admin button
}
else
{
//don't show the button? Grey it out?
}
|
hasRole(String roleName) 主题是否已分配给指定的角色
hasRoles(List<String> roleNames) 是否包含指定的角色
hasAllRoles(Collection<String> roleNames) 是否包含指定的所有角色
角色断言
Subject currentUser = SecurityUtils.getSubject();
//guarantee that the current user is a bank teller and
//therefore allowed to open the account:
currentUser.checkRole(
"bankTeller"
);
openBankAccount();
|
checkRole(String roleName) 断言是否是指定角色
checkRoles(Collection<String> roleNames) 断言是否包含以下角色
checkRoles(String... roleNames) 断言是否包含所有角色
如果判断指定用户是否有权限访问指定名称的打印机
那么就会用到下列几个方法
Permission printPermission =
new
PrinterPermission(
"laserjet4400n"
,
"print"
);
Subject currentUser = SecurityUtils.getSubject();
if
(currentUser.isPermitted(printPermission)) {
//show the Print button
}
else
{
//don't show the button? Grey it out?
}
|
isPermitted(Permission p) 判断主题是否允许执行一个动作
isPermitted(List<Permission> perms) 是否允许执行一组动作
isPermittedAll(Collection<Permission> perms) 是否允许执行所有动作
基于字符串的权限检查
Subject currentUser = SecurityUtils.getSubject();
if
(currentUser.isPermitted(
"printer:print:laserjet4400n"
)) {
//show the Print button
}
else
{
//don't show the button? Grey it out?
}
|
也可以如下使用
Subject currentUser = SecurityUtils.getSubject();
Permission p =
new
WildcardPermission(
"printer:print:laserjet4400n"
);
if
(currentUser.isPermitted(p) {
//show the Print button
}
else
{
//don't show the button? Grey it out?
}
|
权限断言类似于角色断言。
2)annocation方式
The RequiresAuthentication annotation
@RequiresAuthentication
public
void
updateAccount(Account userAccount) {
//this method will only be invoked by a
//Subject that is guaranteed authenticated
...
}
|
等同于下述代码
public
void
updateAccount(Account userAccount) {
if
(!SecurityUtils.getSubject().isAuthenticated()) {
throw
new
AuthorizationException(...);
}
//Subject is guaranteed authenticated here
...
}
|
The RequiresGuest annotation
@RequiresGuest
public
void
signUp(User newUser) {
//this method will only be invoked by a
//Subject that is unknown/anonymous
...
}
|
等同于
public
void
signUp(User newUser) {
Subject currentUser = SecurityUtils.getSubject();
PrincipalCollection principals = currentUser.getPrincipals();
if
(principals !=
null
&& !principals.isEmpty()) {
//known identity - not a guest:
throw
new
AuthorizationException(...);
}
//Subject is guaranteed to be a 'guest' here
...
}
|
The RequiresPermissions annotation
@RequiresPermissions
(
"account:create"
)
public
void
createAccount(Account account) {
//this method will only be invoked by a Subject
//that is permitted to create an account
...
}
|
等同于
public
void
createAccount(Account account) {
Subject currentUser = SecurityUtils.getSubject();
if
(!subject.isPermitted(
"account:create"
)) {
throw
new
AuthorizationException(...);
}
//Subject is guaranteed to be permitted here
...
}
|
The RequiresRoles permission
@RequiresRoles
(
"administrator"
)
public
void
deleteUser(User user) {
//this method will only be invoked by an administrator
...
}
|
等同于
public
void
deleteUser(User user) {
Subject currentUser = SecurityUtils.getSubject();
if
(!subject.hasRole(
"administrator"
)) {
throw
new
AuthorizationException(...);
}
//Subject is guaranteed to be an 'administrator' here
...
}
|
The RequiresUser annotation
@RequiresUser
public
void
updateAccount(Account account) {
//this method will only be invoked by a 'user'
//i.e. a Subject with a known identity
...
}
|
等同于
public
void
updateAccount(Account account) {
Subject currentUser = SecurityUtils.getSubject();
PrincipalCollection principals = currentUser.getPrincipals();
if
(principals ==
null
|| principals.isEmpty()) {
//no identity - they're anonymous, not allowed:
throw
new
AuthorizationException(...);
}
//Subject is guaranteed to have a known identity here
...
}
|
授权顺序
1)应用程序调用主题,判断hasRole,isPermitted得到角色或者用户权限的列表。
2)组成对应的授权方法
3)协调如何授权
4)通过桥进行各种方式的授权
web应用
配置web.xml
<listener>
<listener-
class
>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-
class
>
</listener>
...
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-
class
>org.apache.shiro.web.servlet.ShiroFilter</filter-
class
>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
|
如果你愿意你可以自定义一个web应用
<context-param>
<param-name>shiroEnvironmentClass</param-name>
<param-value>com.foo.bar.shiro.MyWebEnvironment</param-value>
</context-param>
|
如果你想改变shiro.ini的位置,那么你可以指定
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>YOUR_RESOURCE_LOCATION_HERE</param-value>
</context-param>
|
shiro.ini中的[urls]配置
例如:
...
[urls]
/index.html = anon
/user/create = anon
/user/** = authc
/admin/** = authc, roles[administrator]
/rest/** = authc, rest
/remoting/rpc/** = authc, perms[
"remote:invoke"
]
|
假如你有如下设置
/account/** = ssl, authc
|
/account下的任何应用程序都将触动ssl和authc链