把 realms 配置给SecurityManager

在认证的时候单个realm是这样配置的:

  <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<!-- 配置session的管理方式 -->
<!-- <property name="sessionMode" value="native"/> -->
<property name="realm" ref="jdbcRealm"/>
</property>
</bean>

多个realm是这样配置的:

  1).将多个realm配置给 authenticator

<!-- 配置多个Realm -->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<property name="realms">
<list>
<ref bean="jdbcRealm"/>
<ref bean="secondRealm"/>
</list>
</property>
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
</property>
</bean>

  2).将 authenticator 配置给 SecurityManager

 <!--
1.配置SecurityManager!
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<!-- 配置session的管理方式 -->
<!-- <property name="sessionMode" value="native"/> -->
<!-- <property name="realm" ref="jdbcRealm"/> -->
<!-- 配置多个Realm -->
<property name="authenticator" ref="authenticator"></property>
</bean>

  其实SecurityManager 中有一个 realms属性

<!--
1.配置SecurityManager!
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<!-- 配置session的管理方式 -->
<!-- <property name="sessionMode" value="native"/> -->
<!-- <property name="realm" ref="jdbcRealm"/> -->
<!-- 配置多个Realm -->
<property name="authenticator" ref="authenticator"></property> <property name="realms"></property>
</bean>

  那么直接在SecurityManager中配置 realms中是否可以呢,答案是可以的。

 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<!-- 配置session的管理方式 -->
<!-- <property name="sessionMode" value="native"/> -->
<!-- <property name="realm" ref="jdbcRealm"/> -->
<!-- 配置多个Realm -->
<property name="authenticator" ref="authenticator"></property> <property name="realms">
<list>
<ref bean="jdbcRealm"/>
<ref bean="secondRealm"/>
</list>
</property>
</bean> <!-- 配置多个Realm -->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
</property>
</bean>

  在授权中是需要将realms改为这样配置的   

  可以再 ModularRealmAuthenticator 的setRealms 中打个断点

  

  代码往前翻可以看到这里做了强制类型转换

授权:

  

 默认拦截器:

  •   Shiro内置了很多默认的拦截器,比如身份验证,授权等相关的。默认拦截器可以参考

    org.apache.shiro.web.filter.mgt.DefaultFilter
    public enum DefaultFilter {
    
        anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
    private final Class<? extends Filter> filterClass; private DefaultFilter(Class<? extends Filter> filterClass) {
    this.filterClass = filterClass;
    } public Filter newInstance() {
    return (Filter) ClassUtils.newInstance(this.filterClass);
    } public Class<? extends Filter> getFilterClass() {
    return this.filterClass;
    } public static Map<String, Filter> createInstanceMap(FilterConfig config) {
    Map<String, Filter> filters = new LinkedHashMap<String, Filter>(values().length);
    for (DefaultFilter defaultFilter : values()) {
    Filter filter = defaultFilter.newInstance();
    if (config != null) {
    try {
    filter.init(config);
    } catch (ServletException e) {
    String msg = "Unable to correctly init default filter instance of type " +
    filter.getClass().getName();
    throw new IllegalStateException(msg, e);
    }
    }
    filters.put(defaultFilter.name(), filter);
    }
    return filters;
    }
    }

    身份验证相关的有:

  授权相关的:

    

  其他:

  

为访问路径配置权限:

  1). 修改页面为 list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body> <h4>List Page</h4> <a href="admin.jsp">Admin Page</a>
<br><br> <a href="user.jsp">User Page</a>
<br><br> <a href="shiro/logout">Logout</a>
</body>
</html>

  2). 在配置文件的过滤器中添加

  

<property name="filterChainDefinitions">
<value>
/login.jsp= anon
/shiro/login= anon
/shiro/logout = logout /user.jsp = roles[user]
/admin.jsp = roles[admin]
# everything else requires authentication: /** = authc
</value>
</property>

  3).授权需要继承 AuthorizingRealm 类,并实现其 doGetAuthorizationInfo 方法

   AuthorizingRealm 类继承自 AuthorizingRealm , 但没有实现 AuthorizingRealm 中的 doGetAuthenticationInfo,

    所以认证和授权 只需要继承 AuthorizingRealm就可以了,同时实现他们两个抽象方法。

  

package com.java.shiro.realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection; public class TestRealm extends AuthorizingRealm { //授权需要实现的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
} //认证需要实现的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
return null;
} }

  查看源码得到,多Realm授权中只要有一个通过就可以 ModularRealmAuthorizer

public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
assertRealmsConfigured();
for (Realm realm : getRealms()) {
if (!(realm instanceof Authorizer)) continue;
if (((Authorizer) realm).hasRole(principals, roleIdentifier)) {
return true;
}
}
return false;
}

  授权Realm的实现

    1). 在原先的ShiroRealm的基础上修改,修改其继承

package com.java.shiro.realms;

import java.util.HashSet;
import java.util.Set; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource; public class ShiroRealm extends AuthorizingRealm { /**
* 用于认证的Realm保持不变
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("[FirstRealm] doGetAuthenticationInfo " + token); // 1. 把AuthenticationToken 转换为UsernamePasswordToken
UsernamePasswordToken up = (UsernamePasswordToken) token;
// 2. 从UsernamePasswordToken 中来获取username
String username = up.getUsername();
// 3. 调用数据库的方法,从数据库中查询username对应的用户记录
System.out.println("从数据库中获取userName :" + username + " 所对应的用户信息.");
// 4. 若用户不存在,则可以抛出 UnknownAccoountException 异常
if ("unknown".equals(username)) {
throw new UnknownAccountException("用户不存在");
}
// 5. 根据用户信息的情况,决定是否需要抛出其他的AuthencationException 异常 假设用户被锁定
if ("monster".equals(username)) {
throw new LockedAccountException("用户被锁定");
}
// 6. 根据用户的情况,来构建AuthenticationInfo 对象并返回,通常使用的是
// SimpleAuthenticationInfo
// 以下信息是从数据库获取的. Object principal = username; // principal 认证的实体信息.
// 可以是username,也可以是数据表对应的用户的实体类对象
// String credentials =
// "fc1709d0a95a6be30bc5926fdb7f22f4";
// // credentials:密码
String credentials = null; // credentials:密码
String realmName = getName();
AuthenticationInfo info = null;/*
* new
* SimpleAuthenticationInfo(principal,
* credentials, realmName);
*/ if ("admin".equals(username)) {
credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
} else if ("user".equals(username)) {
credentials = "098d2c478e9c11555ce2823231e02ec1";
} ByteSource credentialsSalt = ByteSource.Util.bytes(username);// 这里的参数要给个唯一的; info = new SimpleAuthenticationInfo(principal, credentials,
credentialsSalt, realmName); return info;
} public static void main(String[] args) {
String hashAlgorithmName = "MD5";
String credentials = "123456";
int hashIterations = 1024;
ByteSource credentialsSalt = ByteSource.Util.bytes("user");
Object obj = new SimpleHash(hashAlgorithmName, credentials,
credentialsSalt, hashIterations);
System.out.println(obj);
} /**
* 这个是用于授权的Realm
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// 1. 从 PrincipalCollection 中获取来获取登录用户的信息
//由于我们配置了多个Realm 一个返回的是 seconde,一个返回的是认证实体,这两个Realm在配置认证的时候是有顺序地
/**
* <property name="realms">
* <list>
* <ref bean="jdbcRealm"/>
* <ref bean="secondRealm"/>
* </list>
* </property>
*
* 当我们在获取Principal的时候也是有顺序的
*/
Object principal = principals.getPrimaryPrincipal(); // 2. 利用登录用户的信息来判断当前用户的角色或权限(可能需要查询数据库)
Set<String> roles = new HashSet<>();
roles.add("user"); // 这里无论登录的是user 还是 admin 都存放一个user角色
if ("admin".equals(principal)) {
roles.add("admin"); // 如果是admin 授权一个admin角色
}
AuthorizationInfo info = new SimpleAuthorizationInfo(roles);
return info;
}
}

  

  

  由于我们配置了多个Realm 一个返回的是 seconde,一个返回的是认证实体,这两个Realm在配置认证的时候是有顺序地

    <property name="realms">
<list>
<ref bean="jdbcRealm"/>
<ref bean="secondRealm"/>
</list>
</property>

  当我们在获取Principal的时候也是有顺序的

  通过查看源代码

public Object getPrimaryPrincipal() {
if (isEmpty()) {
return null;
}
return iterator().next();
}
public Iterator iterator() {
return asSet().iterator();
}
 public Set asSet() {
if (realmPrincipals == null || realmPrincipals.isEmpty()) {
return Collections.EMPTY_SET;
}
Set aggregated = new LinkedHashSet();
Collection<Set> values = realmPrincipals.values();
for (Set set : values) {
aggregated.addAll(set);
}
if (aggregated.isEmpty()) {
return Collections.EMPTY_SET;
}
return Collections.unmodifiableSet(aggregated);
}

  上述代码第6行得到  realmPrincipals 的类型 LinkedHashMap,只有这样才能保证我得到的是希望的那个值。

启动Tomcat

使用admin登录 可以访问两个页面,user登录只能访问一个页面

  • Permissions

  

  • 授权流程

  

  

  

Shiro-授权的更多相关文章

  1. Apache Shiro 使用手册(三)Shiro 授权

    授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等. 一.授权的三要素 授权有着三 ...

  2. Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  3. Shiro笔记(五)Shiro授权

    Shiro授权 也叫访问控制,即在应用中控制谁能访问那些资源(如访问页面.编辑数据.页面操作等).在授权中需要了解几个关键对象:主体(subject).资源(resource).权限(Permissi ...

  4. Shiro授权管理

    一.授权 授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等).在授权中需了解的几个关键对象:主体(Subject).资源(Resource).权限(Permissi ...

  5. 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权

    原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...

  6. shiro授权-记调试过程

    根据张开涛老师的shiro教程学习过程中 感觉shiro授权这块有点绕 调试了十几遍 大概有个思路  记录一下 1.单元测试入口 2.subject().isPermitted("+user ...

  7. frame shiro 授权及原理简述

    shiro 授权模式 shiro采用的是rbac授权模式rbac,基于角色的权限管理,谁扮演什么角色,被允许做什么事情. shiro 授权流程 shiro 授权方式 1.编程式 通过写if/else授 ...

  8. Apache Shiro 使用手册(三)Shiro 授权(转发:http://kdboy.iteye.com/blog/1155450)

    授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等. 一.授权的三要素 授权有着三 ...

  9. Shiro授权流程

    1,授权中涉及的一些概念      [1]授权:访问控制,即在应用中认证用户能否访问的系统资源(如一个页面,一个按钮等).      [2]资源:在Web应用中反应为用户可以访问的URL.       ...

  10. shiro授权+注解式开发

    shiro授权和注解式开发 1.shiro授权角色.权限 2.Shiro的注解式开发 ShiroUserMapper.xml <select id="getRolesByUserId& ...

随机推荐

  1. .NET简单的语句

    获取当前时间的代码: Response.Write(DateTime.Now); 第一次加载页面的语句: if (!IsPostBack) { Response.Write("这是第一次加载 ...

  2. Hadoop HA的搭建

    1.首先添加hosts文件 vim /etc/hosts 192.168.0.1 MSJTVL-DSJC-H01 192.168.0.2 MSJTVL-DSJC-H03 192.168.0.3 MSJ ...

  3. 关于禁止在 .NET Framework 中执行用户代码。启用 "clr enabled" 配置选项

    这个问题是我新装好sql2008r2以后,我把服务器上的数据库还原到本地,取代码里跟踪测试的时候,出现的这个问题. 然后我在网上找了之后在sql里直接新建查询执行如下语句: exec sp_confi ...

  4. hdu 4772

    题意:给你两个矩阵,一个矩阵旋转90度,180度,270度, 然后和另外一个矩阵进行比较,如果对应值相同,则加一,最后得出最大的值 题目没什么难度....主要是纪念下....貌似这一题是当时比赛前一个 ...

  5. requestAnimationFrame 兼容处理

    (function() { ; var vendors = ['ms', 'moz', 'webkit', 'o']; ; x < vendors.length && !wind ...

  6. CSS优先级总结(转载)

    样式的优先级 多重样式(Multiple Styles):如果外部样式.内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况. 一般情况下,优先级如下: (外部样式)External styl ...

  7. (转)asp.net中Literal与label的区别

    asp.net中Literal与label的区别 一.Literal Web 服务器控件概述(摘于MSDN) 可以使用 Literal Web 服务器控件作为页面上其他内容的容器.Literal 最常 ...

  8. storm-kafka教程

    一.原理介绍   本文内容参考:https://github.com/apache/storm/tree/master/external/storm-kafka#brokerhosts (一)使用st ...

  9. DoingOrder.aspx.cs缓存的使用方法

    using System; using System.Web.UI; using System.Data; using System.Text; using BLL = SmartWaterSys.B ...

  10. 1.2 Coin 项目

    自2009年起,Coin便是Java 7(和Java 8)中一个开源的子项目.创建Coin项目是为了反映Java语言中的微小变动: 修改Java语言,按不同的修改方式及其复杂度依次分为:类库.工具提供 ...