shiro-权限控制框架
2017-12-20 19:12
369 查看
一. shiro简介
Apache Shiro(发音为“shee-roh”,日语“堡垒(Castle)”的意思)是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。
Shiro四要素,提供了保护应用的API:
认证 - 用户身份识别,常被称为用户“登录”;
授权 - 访问控制;
密码加密 - 保护或隐藏数据防止被偷窥;
会话管理 - 每用户相关的时间敏感的状态。
二. shiro特点
易于使用 - 易用性是这个项目的最终目标。应用安全有可能会非常让人糊涂,令人沮丧,并被认为是“必要之恶”【译注:比喻应用安全方面的编程。】。若是能让它简化到新手都能很快上手,那它将不再是一种痛苦了。
广泛性 - 没有其他安全框架可以达到Apache Shiro宣称的广度,它可以为你的安全需求提供“一站式”服务。
灵活性 - Apache Shiro可以工作在任何应用环境中。虽然它工作在Web、EJB和IoC环境中,但它并不依赖这些环境。Shiro既不强加任何规范,也无需过多依赖。
Web能力 - Apache Shiro对Web应用的支持很神奇,允许你基于应用URL和Web协议(如REST)创建灵活的安全策略,同时还提供了一套控制页面输出的JSP标签库。
可插拔 - Shiro干净的API和设计模式使它可以方便地与许多的其他框架和应用进行集成。你将看到Shiro可以与诸如Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin这类第三方框架无缝集成。
ini配置权限信息(参考http://shiro.apache.org/configuration.html)
[html] view
plain copy
# =======================
# Shiro INI configuration
# =======================
[main]
[users]
# 设置用户信息
# 语法是 username = password, roleName1, roleName2, …, roleNameN
jiaozi = 123456,role1
[roles]
# 角色信息和角色拥有的权限
#语法是 rolename = permissionDefinition1, permissionDefinition2, …, permissionDefinitionN
#权限的语法 * 表示所有权限 一般语法是 权限类型.权限动作.权限的资源id 比如 user:delete:1 表示拥有删除1号用户的权限 user:delete:*表示删除所有用户权限
admin = *
role1 = user:query:*, user:delete:1
[urls]
# web中的url过滤
maven项目添加支持
[html] view
plain copy
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
测试验证权限过程(参考http://shiro.apache.org/10-minute-tutorial.html)
[html] view
plain copy
package shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestShiro {
public static void main(String[] args) {
testIni();
}
public static void testIni() {
//从配置文件中读取用户的权限信息
Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
org.apache.shiro.mgt.SecurityManager securityManager = (org.apache.shiro.mgt.SecurityManager)factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//获取登录用户信息
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute( "保存数据的键", "保存数据的值" );
/**
* 用户包括两部分
// * principals and credentials
* principals(本人)表示用户的标识信息 比如用户名 用户地址等
* credentials(凭证)表示用户用于登录的凭证 比如密码 证书等
*/
//isAuthenticated判断是否登录过
if ( !currentUser.isAuthenticated() ) {
//令牌 用户名和密码 其实就是credentials
UsernamePasswordToken token = new UsernamePasswordToken("jiaozi", "123456");
token.setRememberMe(true);
//开始登录操作 操作后 isAuthenticated就是true
currentUser.login(token);
System.out.println("登录成功");
//判断是否有某个角色
if(currentUser.hasRole("role1")){
System.out.println("拥有角色role1");
}
if(currentUser.isPermitted("user:query:1")){
System.out.println("拥有查询1号用户权限");
}
}
currentUser.logout();
}
}
一般权限信息存在于是数据库
我这里模拟放在内存变量map中
添加realm的实现类
[html] view
plain copy
package shiro;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAccount;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定义realm的实现
* @author jiaozi
*
*/
public class MyRealm extends AuthorizingRealm {
//用于存放用户信息
static Map<String,String> userList=null;
//用于存放橘色信息
static Map<String,String> roleList=null;
//每个realm都有一个名字
static String REALM_NAME="myrealm";
static{
//这里也可以从数据库读取
//模拟用户
userList=new HashMap();
userList.put("zs", "123456,role2,role3");
//模拟权限
roleList=new HashMap();
roleList.put("role2","user:query:*");
roleList.put("role3", "user:*");
}
/**
* 支持哪种令牌
*/
@Override
public boolean supports(AuthenticationToken token) {
// TODO Auto-generated method stub
return token instanceof UsernamePasswordToken;
}
/**
* 获取权限过程
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取用户名
String userName=principals.getPrimaryPrincipal().toString();
//构建权限的类
SimpleAuthorizationInfo sai=new SimpleAuthorizationInfo();
Set<String> proleList=new HashSet<String>();
Set<String> stringPermissions=new HashSet<String>();
if(userList.containsKey(userName)){
String[] roles=userList.get(userName).toString().split(",");
for(int i=1;i<roles.length;i++){
proleList.add(roles[i]);
String pp=roleList.get(roles[i]);
String[] ppArry=pp.split(",");
for(int j=0;j<ppArry.length;j++){
stringPermissions.add(ppArry[j]);
}
}
}
sai.setRoles(proleList);
sai.setStringPermissions(stringPermissions);
return sai;
}
/**
* 认证过程
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upt=(UsernamePasswordToken)token;
String userName=token.getPrincipal().toString();
String password=String.valueOf(upt.getPassword());
if(userList.containsKey(userName)){
String realPwd=userList.get(userName).toString().split(",")[0];
if(realPwd.equals(password)){
SimpleAccount sa=new SimpleAccount(userName,password,"REALM_NAME");
return sa;
}
}
return null;
}
}
ini配置文件中配置该realm main的部分添加
[html] view
plain copy
[main]
# 定义securityManager, Realms and 其他
myRealm= shiro.MyRealm
securityManager.realms=$iniRealm , $myRealm
#iniRealm是内置的默认realm读取ini文件的传入 如果自定义了realm该realm被替代 如果还想使用可以直接引用
#如果有多个realm 策略是所有的realm都要验证通过 还是只需要一个验证通过 我这里只需要一个验证通过 默认是所有
#参考http://shiro.apache.org/authentication.html
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
在之前例子基础上进行拓展 添加war项目 添加shiro-web依赖
[html] view
plain copy
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
web.xml添加shiro支持的过滤器和ini文件路径配置参数
[html] view
plain copy
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>/WEB-INF/shiro.ini</param-value>
</context-param>
<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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
添加几个html和jsp用于测试
login.html添加用于登录的表单
[html] view
plain copy
<form action="loginServlet" method="post">
用戶名 :<input type="text" name="userName"/>
密碼:<input type="text" name="password"/>
<input type="submit">
</form>
添加query.jsp用于当登录成功后跳转的页面
[html] view
plain copy
<body>
這是測試查詢頁面
</body>
添加add.jsp用于测试拥有某个角色才能进入的页面
[html] view
plain copy
<body>
這是測試新增頁面
</body>
添加一个检测没有角色失败页面 un.jsp
[html] view
plain copy
<body>
没有权限
</body
t添加一个登录的servlet
web.xml
[html] view
plain copy
<servlet>
<description></description>
<display-name>LoginServlet</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.et.web.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
servlet类
[html] view
plain copy
package cn.et.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 登录进入方法
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken upt=new UsernamePasswordToken(request.getParameter("userName"), request.getParameter("password"));
try {
subject.login(upt);
request.getRequestDispatcher("/query.jsp").forward(request, response);
} catch (AuthenticationException e) {
request.getRequestDispatcher("/login.html").forward(request, response);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
修改shiro.ini添加路径过滤
[html] view
plain copy
# =======================
# Shiro INI configuration
# =======================
[main]
# 定义securityManager, Realms and 其他
myRealm= shiro.MyRealm
securityManager.realms=$iniRealm , $myRealm
#如果有多个realm 策略是所有的realm都要验证通过 还是只需要一个验证通过 我这里只需要一个验证通过 默认是所有
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
authc.loginUrl = /login.html
#如果沒有登錄 會先跳轉到loginUrl 如果登錄了沒權限 跳轉到unauthorizedUrl指定頁面
roles.loginUrl= /login.html
roles.unauthorizedUrl= /un.html
[users]
# 设置用户信息
# 语法是 username = password, roleName1, roleName2, …, roleNameN
jiaozi = 123456,role1
[roles]
# 角色信息和角色拥有的权限
#语法是 rolename = permissionDefinition1, permissionDefinition2, …, permissionDefinitionN
#权限的语法 * 表示所有权限 一般语法是 权限类型.权限动作.权限的资源id 比如 user:delete:1 表示拥有删除1号用户的权限 user:delete:*表示删除所有用户权限
admin = *
role1 = user:query:*, user:delete:1
[urls]
# web中的url过滤
#語法是 某個路徑 = 怎麼樣過濾1,過濾2 常用的過濾有
# anon 匿名用戶
# authc 表示用戶和密碼驗證過濾 類 org.apache.shiro.web.filter.authc.FormAuthenticationFilter 沒有登錄自動跳轉到登錄頁
# perms 是否擁有某些權限過濾 類 org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 用法 perms["remote:invoke"]
# roles是否擁有某個角色 org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 用法roles[administrator]
# user 是否是某個用戶 org.apache.shiro.web.filter.authc.UserFilter
# 也可以在main中自定義filter url就可以應用 參考http://shiro.apache.org/web.html#programmatic-support
/login.html = anon
/loginServlet = anon
/query.jsp = authc
/add.jsp = roles[role2]
添加maven的jsp支持和shiro-spring和springboot
[html] view
plain copy
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
&n
20000
bsp; <version>1.2</version>
</dependency>
</dependencies>
html和realm还是之前的 ini文件被替换成在spring中配置 添加配置的bean
[html] view
plain copy
package cn.et.boot;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import shiro.MyRealm;
@Configuration
public class Config {
/**
* 等價于 web.xml配置
* 自動 將 /*的請求 委託給spring容器中 bean名字和filter-name一致的bean處理
*
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* @return
*/
@Bean
public FilterRegistrationBean webShiroFilter(){
FilterRegistrationBean frb=new FilterRegistrationBean();
DelegatingFilterProxy dfp=new DelegatingFilterProxy();
frb.setFilter(dfp);
frb.setName("shiroFilter");
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("/*");
frb.setUrlPatterns(linkedHashSet);
Map<String, String> initParameters=new HashMap<String, String>();
initParameters.put("targetFilterLifecycle", "true");
frb.setInitParameters(initParameters);
return frb;
}
/**
* 配置我的realm
* @return
*/
@Bean
public Realm myRealm(){
return new MyRealm();
}
/**
* 定義默認的securityManager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(@Autowired Realm myRealm){
DefaultWebSecurityManager dwm=new DefaultWebSecurityManager();
dwm.setRealm(myRealm);
return dwm;
}
/**
* 定義和過濾器一致名字的ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(@Autowired org.apache.shiro.mgt.SecurityManager securityManager){
ShiroFilterFactoryBean sffb=new ShiroFilterFactoryBean();
sffb.setSecurityManager(securityManager);
sffb.setLoginUrl("/login.html");
sffb.setUnauthorizedUrl("/un.jsp");
Map<String, String> urls=new HashMap<String, String>();
/*
* 定义url
/login.html = anon
/loginServlet = anon
/query.jsp = authc
/add.jsp = roles[role2]
* */
urls.put("/login.html", "anon");
urls.put("/loginServlet", "anon");
urls.put("/query.jsp", "authc");
urls.put("/add.jsp", "roles[role1]");
sffb.setFilterChainDefinitionMap(urls);
return sffb;
}
/**
* 定義後置處理器
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
}
将之前servlet替换成springmvc的controller
[html] view
plain copy
package cn.et.boot;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
@RequestMapping("loginServlet")
public String login(String userName,String password){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken upt=new UsernamePasswordToken(userName,password);
try {
subject.login(upt);
return "/query.jsp";
} catch (AuthenticationException e) {
return "redirect:/login.html";
}
}
}
添加一个springboot启动类 just run
[html] view
plain copy
package cn.et.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
Apache Shiro(发音为“shee-roh”,日语“堡垒(Castle)”的意思)是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。
Shiro四要素,提供了保护应用的API:
认证 - 用户身份识别,常被称为用户“登录”;
授权 - 访问控制;
密码加密 - 保护或隐藏数据防止被偷窥;
会话管理 - 每用户相关的时间敏感的状态。
二. shiro特点
易于使用 - 易用性是这个项目的最终目标。应用安全有可能会非常让人糊涂,令人沮丧,并被认为是“必要之恶”【译注:比喻应用安全方面的编程。】。若是能让它简化到新手都能很快上手,那它将不再是一种痛苦了。
广泛性 - 没有其他安全框架可以达到Apache Shiro宣称的广度,它可以为你的安全需求提供“一站式”服务。
灵活性 - Apache Shiro可以工作在任何应用环境中。虽然它工作在Web、EJB和IoC环境中,但它并不依赖这些环境。Shiro既不强加任何规范,也无需过多依赖。
Web能力 - Apache Shiro对Web应用的支持很神奇,允许你基于应用URL和Web协议(如REST)创建灵活的安全策略,同时还提供了一套控制页面输出的JSP标签库。
可插拔 - Shiro干净的API和设计模式使它可以方便地与许多的其他框架和应用进行集成。你将看到Shiro可以与诸如Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin这类第三方框架无缝集成。
ini配置权限信息(参考http://shiro.apache.org/configuration.html)
[html] view
plain copy
# =======================
# Shiro INI configuration
# =======================
[main]
[users]
# 设置用户信息
# 语法是 username = password, roleName1, roleName2, …, roleNameN
jiaozi = 123456,role1
[roles]
# 角色信息和角色拥有的权限
#语法是 rolename = permissionDefinition1, permissionDefinition2, …, permissionDefinitionN
#权限的语法 * 表示所有权限 一般语法是 权限类型.权限动作.权限的资源id 比如 user:delete:1 表示拥有删除1号用户的权限 user:delete:*表示删除所有用户权限
admin = *
role1 = user:query:*, user:delete:1
[urls]
# web中的url过滤
maven项目添加支持
[html] view
plain copy
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
测试验证权限过程(参考http://shiro.apache.org/10-minute-tutorial.html)
[html] view
plain copy
package shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class TestShiro {
public static void main(String[] args) {
testIni();
}
public static void testIni() {
//从配置文件中读取用户的权限信息
Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
org.apache.shiro.mgt.SecurityManager securityManager = (org.apache.shiro.mgt.SecurityManager)factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//获取登录用户信息
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute( "保存数据的键", "保存数据的值" );
/**
* 用户包括两部分
// * principals and credentials
* principals(本人)表示用户的标识信息 比如用户名 用户地址等
* credentials(凭证)表示用户用于登录的凭证 比如密码 证书等
*/
//isAuthenticated判断是否登录过
if ( !currentUser.isAuthenticated() ) {
//令牌 用户名和密码 其实就是credentials
UsernamePasswordToken token = new UsernamePasswordToken("jiaozi", "123456");
token.setRememberMe(true);
//开始登录操作 操作后 isAuthenticated就是true
currentUser.login(token);
System.out.println("登录成功");
//判断是否有某个角色
if(currentUser.hasRole("role1")){
System.out.println("拥有角色role1");
}
if(currentUser.isPermitted("user:query:1")){
System.out.println("拥有查询1号用户权限");
}
}
currentUser.logout();
}
}
一般权限信息存在于是数据库
我这里模拟放在内存变量map中
添加realm的实现类
[html] view
plain copy
package shiro;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAccount;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定义realm的实现
* @author jiaozi
*
*/
public class MyRealm extends AuthorizingRealm {
//用于存放用户信息
static Map<String,String> userList=null;
//用于存放橘色信息
static Map<String,String> roleList=null;
//每个realm都有一个名字
static String REALM_NAME="myrealm";
static{
//这里也可以从数据库读取
//模拟用户
userList=new HashMap();
userList.put("zs", "123456,role2,role3");
//模拟权限
roleList=new HashMap();
roleList.put("role2","user:query:*");
roleList.put("role3", "user:*");
}
/**
* 支持哪种令牌
*/
@Override
public boolean supports(AuthenticationToken token) {
// TODO Auto-generated method stub
return token instanceof UsernamePasswordToken;
}
/**
* 获取权限过程
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取用户名
String userName=principals.getPrimaryPrincipal().toString();
//构建权限的类
SimpleAuthorizationInfo sai=new SimpleAuthorizationInfo();
Set<String> proleList=new HashSet<String>();
Set<String> stringPermissions=new HashSet<String>();
if(userList.containsKey(userName)){
String[] roles=userList.get(userName).toString().split(",");
for(int i=1;i<roles.length;i++){
proleList.add(roles[i]);
String pp=roleList.get(roles[i]);
String[] ppArry=pp.split(",");
for(int j=0;j<ppArry.length;j++){
stringPermissions.add(ppArry[j]);
}
}
}
sai.setRoles(proleList);
sai.setStringPermissions(stringPermissions);
return sai;
}
/**
* 认证过程
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upt=(UsernamePasswordToken)token;
String userName=token.getPrincipal().toString();
String password=String.valueOf(upt.getPassword());
if(userList.containsKey(userName)){
String realPwd=userList.get(userName).toString().split(",")[0];
if(realPwd.equals(password)){
SimpleAccount sa=new SimpleAccount(userName,password,"REALM_NAME");
return sa;
}
}
return null;
}
}
ini配置文件中配置该realm main的部分添加
[html] view
plain copy
[main]
# 定义securityManager, Realms and 其他
myRealm= shiro.MyRealm
securityManager.realms=$iniRealm , $myRealm
#iniRealm是内置的默认realm读取ini文件的传入 如果自定义了realm该realm被替代 如果还想使用可以直接引用
#如果有多个realm 策略是所有的realm都要验证通过 还是只需要一个验证通过 我这里只需要一个验证通过 默认是所有
#参考http://shiro.apache.org/authentication.html
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
在之前例子基础上进行拓展 添加war项目 添加shiro-web依赖
[html] view
plain copy
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
web.xml添加shiro支持的过滤器和ini文件路径配置参数
[html] view
plain copy
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>/WEB-INF/shiro.ini</param-value>
</context-param>
<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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
添加几个html和jsp用于测试
login.html添加用于登录的表单
[html] view
plain copy
<form action="loginServlet" method="post">
用戶名 :<input type="text" name="userName"/>
密碼:<input type="text" name="password"/>
<input type="submit">
</form>
添加query.jsp用于当登录成功后跳转的页面
[html] view
plain copy
<body>
這是測試查詢頁面
</body>
添加add.jsp用于测试拥有某个角色才能进入的页面
[html] view
plain copy
<body>
這是測試新增頁面
</body>
添加一个检测没有角色失败页面 un.jsp
[html] view
plain copy
<body>
没有权限
</body
t添加一个登录的servlet
web.xml
[html] view
plain copy
<servlet>
<description></description>
<display-name>LoginServlet</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.et.web.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
servlet类
[html] view
plain copy
package cn.et.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 登录进入方法
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken upt=new UsernamePasswordToken(request.getParameter("userName"), request.getParameter("password"));
try {
subject.login(upt);
request.getRequestDispatcher("/query.jsp").forward(request, response);
} catch (AuthenticationException e) {
request.getRequestDispatcher("/login.html").forward(request, response);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
修改shiro.ini添加路径过滤
[html] view
plain copy
# =======================
# Shiro INI configuration
# =======================
[main]
# 定义securityManager, Realms and 其他
myRealm= shiro.MyRealm
securityManager.realms=$iniRealm , $myRealm
#如果有多个realm 策略是所有的realm都要验证通过 还是只需要一个验证通过 我这里只需要一个验证通过 默认是所有
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
authc.loginUrl = /login.html
#如果沒有登錄 會先跳轉到loginUrl 如果登錄了沒權限 跳轉到unauthorizedUrl指定頁面
roles.loginUrl= /login.html
roles.unauthorizedUrl= /un.html
[users]
# 设置用户信息
# 语法是 username = password, roleName1, roleName2, …, roleNameN
jiaozi = 123456,role1
[roles]
# 角色信息和角色拥有的权限
#语法是 rolename = permissionDefinition1, permissionDefinition2, …, permissionDefinitionN
#权限的语法 * 表示所有权限 一般语法是 权限类型.权限动作.权限的资源id 比如 user:delete:1 表示拥有删除1号用户的权限 user:delete:*表示删除所有用户权限
admin = *
role1 = user:query:*, user:delete:1
[urls]
# web中的url过滤
#語法是 某個路徑 = 怎麼樣過濾1,過濾2 常用的過濾有
# anon 匿名用戶
# authc 表示用戶和密碼驗證過濾 類 org.apache.shiro.web.filter.authc.FormAuthenticationFilter 沒有登錄自動跳轉到登錄頁
# perms 是否擁有某些權限過濾 類 org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 用法 perms["remote:invoke"]
# roles是否擁有某個角色 org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 用法roles[administrator]
# user 是否是某個用戶 org.apache.shiro.web.filter.authc.UserFilter
# 也可以在main中自定義filter url就可以應用 參考http://shiro.apache.org/web.html#programmatic-support
/login.html = anon
/loginServlet = anon
/query.jsp = authc
/add.jsp = roles[role2]
添加maven的jsp支持和shiro-spring和springboot
[html] view
plain copy
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
&n
20000
bsp; <version>1.2</version>
</dependency>
</dependencies>
html和realm还是之前的 ini文件被替换成在spring中配置 添加配置的bean
[html] view
plain copy
package cn.et.boot;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import shiro.MyRealm;
@Configuration
public class Config {
/**
* 等價于 web.xml配置
* 自動 將 /*的請求 委託給spring容器中 bean名字和filter-name一致的bean處理
*
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* @return
*/
@Bean
public FilterRegistrationBean webShiroFilter(){
FilterRegistrationBean frb=new FilterRegistrationBean();
DelegatingFilterProxy dfp=new DelegatingFilterProxy();
frb.setFilter(dfp);
frb.setName("shiroFilter");
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("/*");
frb.setUrlPatterns(linkedHashSet);
Map<String, String> initParameters=new HashMap<String, String>();
initParameters.put("targetFilterLifecycle", "true");
frb.setInitParameters(initParameters);
return frb;
}
/**
* 配置我的realm
* @return
*/
@Bean
public Realm myRealm(){
return new MyRealm();
}
/**
* 定義默認的securityManager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(@Autowired Realm myRealm){
DefaultWebSecurityManager dwm=new DefaultWebSecurityManager();
dwm.setRealm(myRealm);
return dwm;
}
/**
* 定義和過濾器一致名字的ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(@Autowired org.apache.shiro.mgt.SecurityManager securityManager){
ShiroFilterFactoryBean sffb=new ShiroFilterFactoryBean();
sffb.setSecurityManager(securityManager);
sffb.setLoginUrl("/login.html");
sffb.setUnauthorizedUrl("/un.jsp");
Map<String, String> urls=new HashMap<String, String>();
/*
* 定义url
/login.html = anon
/loginServlet = anon
/query.jsp = authc
/add.jsp = roles[role2]
* */
urls.put("/login.html", "anon");
urls.put("/loginServlet", "anon");
urls.put("/query.jsp", "authc");
urls.put("/add.jsp", "roles[role1]");
sffb.setFilterChainDefinitionMap(urls);
return sffb;
}
/**
* 定義後置處理器
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
}
将之前servlet替换成springmvc的controller
[html] view
plain copy
package cn.et.boot;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
@RequestMapping("loginServlet")
public String login(String userName,String password){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken upt=new UsernamePasswordToken(userName,password);
try {
subject.login(upt);
return "/query.jsp";
} catch (AuthenticationException e) {
return "redirect:/login.html";
}
}
}
添加一个springboot启动类 just run
[html] view
plain copy
package cn.et.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
相关文章推荐
- 项目权限控制的管家——Apache Shiro框架
- shiro权限控制(一):shiro介绍以及整合SSM框架
- [笔记-架构探险]框架优化与功能扩展3.2.安全框架shiro、提供安全控制特性2-jsp页面标签和框架aop启用权限控制
- java权限控制框架shiro
- shiro---认识权限控制框架
- shiro安全框架扩展教程--如何动态控制页面节点元素的权限
- 权限控制框架-shiro
- 权限控制框架 - shiro
- 权限控制框架-shiro
- Apache Shiro权限控制框架简介
- 权限控制之Shiro框架--初步了解篇
- 权限控制框架Spring Security 和Shiro 的总结
- 权限控制框架Shiro简单介绍及配置实例
- 权限控制框架Shiro总结
- shiro 权限控制框架 入门级实例(二)注册加密
- 在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制
- shiro框架之动态URL权限控制 十九
- Shiro权限控制框架入门1:Shiro的认证流程以及基本概念介绍
- Shiro + SSM(框架) + Freemarker(jsp)讲解的权限控制
- shiro 权限控制框架