shiro框架---解决权限限制问题

shiro简介

26213939_fb0B.jpg

Apache Shiro是一个强大而灵活的开源安全框架,它能够干净利落地处理身份认证,授权,企业会话管理和加密(核心功能)。

以下是你可以用 Apache Shiro所做的事情: 

1. 验证用户

2.对用户执行访问控制,如: 

      判断用户是否拥有角色admin。

      判断用户是否拥有访问的权限

3.在任何环境下使用 Session API。例如CS程序。

4.可以使用多个用户数据源。例如一个是oracle用户库,另外一个是mysql用户库。

5. 单点登录(SSO)功能。 

6.“Remember Me”服务 ,类似购物车的功能,shiro官方建议开启

shiro框架执行流程

26213938_I2IT.jpg

Application Code:应用程序代码,由开发人员负责开发

subject:主体,当前用户

security manager:安全管理器,框架的核心,负责调用realm,框架提供

realm:类似于dao,访问安全数据(权限、角色、用户),框架提供,也可以自定义

权限控制方式:

方式一:URL拦截方式

26213938_3FAW.png

第一步:导包

26213940_5Cka.png

第二步:在web.xml里面配置由spring框架提供整合shero的过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 指定spring配置文件 -->
< context-param >
   < param-name >contextConfigLocation</ param-name >
   < param-value >classpath:applicationContext.xml</ param-value >
</ context-param >
 
< listener >
   < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class >
</ listener >
 
<!-- 配置权限管理 -->
< filter >
   < filter-name >shiroFilter</ filter-name >
   < filter-class >org.springframework.web.filter.DelegatingFilterProxy</ filter-class >
</ filter >
< filter-mapping >
   < filter-name >shiroFilter</ filter-name >
   < url-pattern >/*</ url-pattern >
</ filter-mapping >

第三步:在applicationContext.xml里面配置一个bean,并且id要和过滤器的名字一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 第一种代码配置设置shiro权限 -->
     < bean id = "shiroFilter" class = "org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
         < property name = "securityManager" ref = "securityManager" ></ property >
         < property name = "loginUrl" value = "/login.jsp" ></ property >
         < property name = "successUrl" value = "/index.jsp" ></ property >
         < property name = "unauthorizedUrl" value = "/500.jsp" ></ property >
         < property name = "filterChainDefinitions" >
             < value >
                 /css/**=anon
                 /js/**=anon
                 /images/**=anon
                 /login.jsp*=anon
                 /validatecode.jsp*=anon
                 /UserAction_login.action*=anon
                 /page_base_staff.action=perms["staff"]
                 /**=authc
             </ value >
         </ property >
     </ bean >

第四步:在applicationConte.xml里面配置安全管理器,并且注入Realm

1
2
3
4
5
< bean id = "securityManager" class = "org.apache.shiro.web.mgt.DefaultWebSecurityManager" >
         < property name = "realms" ref = "shiroRealms" ></ property >
         < property name = "cacheManager" ref = "cache" ></ property >
     </ bean >
     < bean id = "shiroRealms" class = "com.mickeymouse.bos.shiro.ShiroRealms" ></ bean >

第五步:编写一个realm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.mickeymouse.bos.shiro;
 
import java.util.List;
 
import javax.annotation.Resource;
 
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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;
import org.springframework.beans.factory.annotation.Autowired;
 
import com.mickeymouse.bos.dao.IFunctionDao;
import com.mickeymouse.bos.dao.IUserDao;
import com.mickeymouse.bos.domain.Function;
import com.mickeymouse.bos.domain.User;
 
public class ShiroRealms extends AuthorizingRealm{
     @Autowired
     private IUserDao iUserDao;
     @Resource
     private IFunctionDao iFunctionDao;
     /**
      * 授权
      */
     @Override
     protected AuthorizationInfo doGetAuthorizationInfo(
             PrincipalCollection principals) {
         //获取认证信息
         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
         //通过认证信息获取当前用户
         User user = (User) principals.getPrimaryPrincipal();
         //先判断是不是超管
         if (user.getUsername()== "admin" ) {
             //超管:直接查询所有权限
             List<Function> list = iFunctionDao.findAll();
             for (Function function : list) {
                 authorizationInfo.addStringPermission( function .getCode());
             }
         } else {
             //普通用户:通过用户ID查询所具有的权限
             List<Function> list = iFunctionDao.findFunctionByUserid(user.getId());
             for (Function function : list) {
                 authorizationInfo.addStringPermission( function .getCode());
             }
         }
         return authorizationInfo;
     }
     /**
      * 认证:判断用户名与密码是否正确
      */
     @Override
     protected AuthenticationInfo doGetAuthenticationInfo(
             AuthenticationToken token) throws AuthenticationException {
         //通过认证标记获取传入的用户名
         UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
         String username = usernamePasswordToken.getUsername();
         //通过用户名查询数据库返回对象
         User user = iUserDao.findByUserFronUsername(username);
         if (user== null ) {
             //如果为空直接返回null,此时subject会直接抛出异常
             return null ;
         } else {
             //账号存在,将从数据库中查询出的密码交给安全管理器比对
             //三个参数:第一个验证正确后需要的返回值,第二个:安全管理器需要的比对密码,第三个:realm的类名
             //简单认证信息对象
             AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(), this .getName());
             return authenticationInfo;
         }
     }
}

第六步:使用shero框架完成登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
  * 登录
  * @return
  */
public String login(){
     String key = ( String ) ActionContext.getContext().getSession(). get ( "key" );
     //取出用户名密码为空
     if (!StringUtils.isEmpty(t.getUsername())&&!StringUtils.isEmpty(t.getPassword())) {
         //去除验证码错误或空
         if (!StringUtils.isEmpty(checkcode)&&!StringUtils.isEmpty(key)&&key.equals(checkcode)) {
             //获取当前用户,此时的状态为"未认证"
             Subject subject = SecurityUtils.getSubject();
             //创建用户名和密码的认证标记
             AuthenticationToken authenticationToken  = new UsernamePasswordToken(t.getUsername(), MD5Utils.md5(t.getPassword()));
             try {
                 //调用登录方法,传入认证标记
                 subject.login(authenticationToken);
                 //如果没有异常,那么返回"认证信息传出的返回值对象"
                 User user = (User) subject.getPrincipal();
                 //存入session域中
                 ActionContext.getContext().getSession().put( "User" ,user);
                 return "home" ;
             } catch (Exception e) {
                 e.printStackTrace();
                 this .addActionMessage( "用户名或者密码不正确~" );
             }
         } else {
             this .addActionMessage( "验证码错误!" );
         }
     } else {
         
         this .addActionMessage( "用户名或者密码不能为空!" );
     }
     return "login" ;
}

异常信息:

当用户名错误,认证信息为空抛出异常

26213940_SmIx.png

当密码错误,安全管理器抛出异常

26213940_QztU.png

方式二:注解方式

26213940_Yg7w.png

第一步:导包

第二步:在applicationContext.xml里开启shero注解

1
2
3
4
5
6
<!-- 第二种:注解方式设置shiro权限 -->
     <!-- 1 . 开启shiro注解 -->
     <bean id= "defaultAdvisorAutoProxyCreator" class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" >
         <property name= "proxyTargetClass" value= "true" ></property>
     </bean>
     <bean class = "org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor" ></bean>

第三步:在Action的方法上使用shiro注解描述需要具有的权限

1
2
3
4
5
6
7
8
9
10
11
/**
  * 分页查询
  */
@RequiresPermissions (value= "region" ) //执行这个方法需要具有region.query这个权限
@RequiresRoles (value= "admin" )
public String pageQuery(){
     regionService.pageQuery(pageBean);
     String[] excludes = new String[]{ "subareas" };
     this .writePageBean2Json(pageBean, excludes );
     return NONE;
}

第四步:注意修改action抽取类的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public ActionBase(){
         
         ParameterizedType parameterizedType = null ;
         Type genericSuperclass = this .getClass().getGenericSuperclass();
         if (genericSuperclass instanceof ParameterizedType) {
             parameterizedType = (ParameterizedType) this .getClass().getGenericSuperclass();
         } else {
             //这里的this为shero的代理对象
             parameterizedType = (ParameterizedType) this .getClass().getSuperclass().getGenericSuperclass();
         }
         
                               
         
         //获得BaseAction类定义的泛型数组
         Type[] types = parameterizedType.getActualTypeArguments();
         Class<T> class1 = (Class<T>) types[ 0 ];
         try {
             t = class1.newInstance();
         } catch (InstantiationException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }


转载于:https://my.oschina.net/mickeymouse/blog/522327

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值