当前位置:   article > 正文

shiro实现登录认证与权限授权管理_shior怎么实现权限

shior怎么实现权限

Apache Shiro 是一个强大而灵活的开源安全框架,从官网上,我们基本上可以了解到,她提供的服务非常明确:
1.Authentication(认证)

2.Authorization(授权)

3.Session Management(会话管理)

4.Cryptography(加密)

1.maven配置

        <!--处理登录相关依赖包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-cas</artifactId>
            <version>1.2.0</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2 在web.xml中添加shiro过滤器

 <!--shiro过滤-->
    <filter>
      <!--因为filter比bean先加载,也就是spring会先加载filter指定的类到container中,
        这样filter中注入的spring bean就为null了。
        解决办法:先filter中加入DelegatingFilterProxy类,"targetFilterLifecycle"指明作用于filter的所有生命周期。
        原理是,DelegatingFilterProxy类是一个代理类,所有的请求都会首先发到这个filter代理,
        然后再按照"filter-name"委派到spring中的这个bean。-->
        
        <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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3 spring中对shiro配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <!-- Shiro Filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!--登录url-->
        <!-- 拦截到,跳转到的地址,通过此地址去认证 -->
        <property name="loginUrl" value="/admin/login.do" />
        <!--登录成功跳转url-->
        <property name="successUrl" value="/login/main.htm"/>
        <!--未授权url,无权限页-->
        <property name="unauthorizedUrl" value="/login/unauthorize.htm"/>
        <property name="filters">
            <map>
                <entry key="authc" value-ref="oAuth2AuthenticationFilter"/>
                <entry key="logout" value-ref="logoutFilter"/>
            </map>
        </property>
        <!--过滤规则-->
        <property name="filterChainDefinitions">
            <value>
                /checkpreload.htm = anon 
                /agent.ateye = anon
                /agent.jveye = anon
                / = authc
                /login/callback.htm = anon
                /login/login.htm = anon
                /login/checkLogin.htm = anon
                /login/unauthorized.htm = anon
                /login/changeSeller.htm = authc
                /login/logout = logout
                /login/api/** = anon
                /login/** = anon
                /** = authc
            </value>
        </property>
    </bean>
    <!--调用org.apache.shiro.SecurityUtils.setSecurityManager方法入参为securityManager,方便日后使用SecurityUtils工具类查询登录相关信息-->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod"
                  value="org.apache.shiro.SecurityUtils.setSecurityManager" />
        <property name="arguments" ref="securityManager" />
    </bean>

    <!-- 配置使用自定义认证器 -->
    <bean id="oauthRealm" class="com.xs.personal.loginServer.common.OauthRealm"/>

    <!-- 核心 securityManager定义 安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--注入realm-->
        <property name="realm" ref="oauthRealm" />
        <!-- 注入session管理器 -->
        <property name="sessionManager" ref="defaultWebSessionManager"/>
        <!-- 注入缓存管理器 使用redis缓存 -->
        <property name="cacheManager" ref="redisCacheManager"/>
    </bean>
	<!-- 缓存管理器 使用redis缓存 -->
    <bean id="redisCacheManager" class="com.alitrip.hotel.helogin.client.shiro.ShiroRedisCacheManager">
      
    </bean>

    <!--会话管理-->
    <!--传统结构项目中,shiro从cookie中读取sessionId以此来维持会话,在前后端分离的项目中
    (也可在移动APP项目使用), 我们选择在ajax的请求头中传递sessionId,因此需要重
    写shiro获取sessionId的方式。 自定义ShiroSessionManager类继承
    DefaultWebSessionManager类,重写getSessionId方法,-->
    <bean id="defaultWebSessionManager" class="org.apache.shiro.web.session.mgt.ShiroSessionManager">
        <!-- session的失效时长,单位毫秒 -->
        <property name="globalSessionTimeout" value="172800000"/>
        <!-- 设置session的失效扫描间隔,单位为毫秒 -->
        <property name="sessionValidationInterval" value="172800000"/>
        <!-- 删除失效的session -->
        <property name="deleteInvalidSessions" value="true"/>
        <!-- 需要让此session可以使用该定时调度器进行检测,注意持久化环境下会非常耗内存 -->
        <property name="sessionValidationSchedulerEnabled" value="false"/>
        <!--sheduler-->
        <!-- 定义要使用的无效Session定时调度器 -->
        <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
        <!-- 定义Session持久化 -->
        <property name="sessionDAO" ref="sessionDAO"/>
        <!-- 所有的session一定要将id设置到Cookie之中,需要提供有Cookie的操作模版 -->
        <property name="sessionIdCookie" ref="sessionIdCookie"/>
        <!-- 定义sessionIdCookie模版可以进行操作的启用 -->
        <property name="sessionIdCookieEnabled" value="true"/>
    </bean>

    <!-- 配置Session DAO的操作处理 -->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <!-- 设置session缓存的名字,这个名字可以任意 -->
        <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
        <!-- 定义该Session DAO操作中所使用的ID生成器 -->
        <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
    </bean>
    <!-- 定义Session ID生成管理器 -->
    <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />

    <!-- 会话Cookie模板 session保存到cookie 关闭浏览器下次可以直接登录认证 2天过期-->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <!-- 设置Cookie名字, 默认为: JSESSIONID 会与SERVLET容器名冲突, 如JETTY, TOMCAT ,重命名-->
        <constructor-arg value="sid"/>
        <!--如果您在cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击-->
        <property name="httpOnly" value="true"/>
        <!-- 定义Cookie的过期时间,单位为秒,如果设置为-1表示浏览器关闭,则Cookie消失 -->
        <property name="maxAge" value="172800000"/>
    </bean>

    <!--默认一分钟验证session是否过期(timestamp 和 timeout)2天过期-->
    <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
        <!-- 随后还需要定义有一个会话管理器的程序类的引用 -->
        <property name="sessionManager" ref="defaultWebSessionManager"/>
        <!-- 设置session的失效扫描间隔,单位为毫秒 -->
        <property name="sessionValidationInterval" value="172800000"/>
    </bean>

    <bean id="oAuth2AuthenticationFilter"
          class="com.。。。。">
    </bean>
    <bean id="logoutFilter" class="com.。。。。"/>

</beans>
  • 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
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

property name="filters"可以配置我们自定义的filter
shiron自带的filter如下我们可以继承这些filter来实现自己需要的一些功能,这些filter也就是filterChainDefinitions过滤规则所执行的filter我们可以根据过滤条件选择我们需要继承的filter

Filter NameClass含义
anonorg.apache.shiro.web.filter.authc.AnonymousFilter没有参数,表示可以匿名使用。
authcorg.apache.shiro.web.filter.authc.FormAuthenticationFilter表示需要认证(登录)才能使用,没有参数
authcBasicorg.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter没有参数表示httpBasic认证
logoutorg.apache.shiro.web.filter.authc.LogoutFilter
noSessionCreationorg.apache.shiro.web.filter.session.NoSessionCreationFilter
permsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms[“user:add:,user:modify:”],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
portorg.apache.shiro.web.filter.authz.PortFilter当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。
restorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilter根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
rolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles[“admin,guest”],每个参数通过才算通过,相当于hasAllRoles()方法。
sslorg.apache.shiro.web.filter.authz.SslFilter表示安全的url请求,协议为https
userorg.apache.shiro.web.filter.authc.UserFilter没有参数表示必须存在用户,当登入操作时不做检查

cacheManager和sessionDAO的区别:
cacheManager缓存里可以包含权限认证的缓存、用户及权限信息的缓存等,也可以做session缓存。但是sessionDAO顾名思义就是做session持久化的,只是它刚好可以使用redis来存储而已。是完全不同的两个概念,通俗来说cacheManager是用来存储用户信息的sessionDAO是用来做session缓存的。

4 自定义Shiro缓存管理器

public class ShiroRedisCacheManager implements CacheManager, Initializable, Destroyable {


    private String keyPrefix = "shiro_redis_cache:";
    //ShiroRedisManager 为redis工具类
    private ShiroRedisManager redisManager;
    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
       //RedisCache为Cache 实现类 实现类方法内通过redisManager进行数据操作
        Cache c  = new RedisCache<K, V>(redisManager, keyPrefix);

        return c;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

实现CacheManager接口就可以了

4.getSessionId的重写

/** * Description:shiro框架 自定义session获取方式 *
可自定义session获取规则。这里采用ajax请求头authToken携带sessionId的方式 * **/ public
class ShiroSessionManager extends DefaultWebSessionManager {

private static final String AUTHORIZATION = "authToken";

private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";

public ShiroSessionManager(){
    super();
}

@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response){
    String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
    System.out.println("id:"+id);
    if(StringUtils.isEmpty(id)){
        //如果没有携带id参数则按照父类的方式在cookie进行获取
        System.out.println("super:"+super.getSessionId(request, response));
        return super.getSessionId(request, response);
    }else{
        //如果请求头中有 authToken 则其值为sessionId    request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);
        return id;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

5 自定义Realm编码

public class OauthRealm extends AuthorizingRealm {
	// 设置realm的名称
	@Override
	public void setName(String name) {
		super.setName("customRealm");
	}
 
	@Autowired
	private AdminUserService adminUserService;
 
	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 
		// token中包含用户输入的用户名和密码
		// 第一步从token中取出用户名
		String userName = (String) token.getPrincipal();
		// 第二步:根据用户输入的userCode从数据库查询
		TAdminUser adminUser = adminUserService.getAdminUserByUserName(userName);
		// 如果查询不到返回null
		if (adminUser == null) {//
			return null;
		}
		// 获取数据库中的密码
		String password = adminUser.getPassword();
		/**
		 * 认证的用户,正确的密码
		 */
 
		return SimpleAuthenticationInfo(adminUser, token.getCredentials(), getName());
	}
 
	/**
	 * 授权,只有成功通过doGetAuthenticationInfo方法的认证后才会执行。
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 从 principals获取主身份信息
		// 将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型),
		TAdminUser activeUser = (TAdminUser)SecurityUtils.getSubject().getPrincipal();
		// 根据身份信息获取权限信息
		// 从数据库获取到角色数据
		TAdminRole roles= adminUserService.getAdminRoles(activeUser);
		//遍历角色下的功能位
		for (RoleDO role : roles) {
        Set<String> permissionList = new HashSet<>();
        List functionBits = role.getFunctionBitList();
        for (int i = 0; i < functionBits.size(); i++) {
            permissionList.add(functionBits.get(i) + "");
        }
         //将功能位列表就是最终的权限 通过在控制层@RequiresPermissions("3")注解限制权限为3才可以访问
        info.addStringPermissions(permissionList);
    }
		return simpleAuthorizationInfo;
  • 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
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号