Shiro系统权限管理、及原理剖析

编程入门 行业动态 更新时间:2024-10-24 14:16:01

Shiro系统<a href=https://www.elefans.com/category/jswz/34/1771295.html style=权限管理、及原理剖析"/>

Shiro系统权限管理、及原理剖析

1.简介       


        常用的Java EE安全框架有shiro、spring security。shiro被应用非常广泛,可以集成cas,搭建单点登录系统。spring security则被认为比较重,应用没有shiro广泛。shiro提供用户名、密码验证,及密码的加密存储,会话Session的管理,与web集成,支持HTTPS的拦截。


2.Shiro原理简析


shiro 原理剖析:

       shiro的核心是java servlet规范中的filter,通过配置拦截器,使用拦截器链来拦截请求,如果允许访问,则通过。通常情况下,系统的登录、退出会配置拦截器。登录的时候,调用subject.login(token),token是用户验证信息,这个时候会在Realm中doGetAuthenticationInfo方法中进行认证。这个时候会把用户提交的验证信息与数据库中存储的认证信息进行比较,一致则允许访问,并在浏览器种下此次回话的cookie,在服务器端存储session信息。退出的时候,调用subject.logout(),会清除回话信息。
      shiro中核心概念介绍:          Filter:                  1.AnonymousFilter:通过此filter修饰的url,任何人都可以进行访问,即使没有进行权限认证 2.FormAuthenticationFilter:通过此filter修饰的url,会对请求的url进行验证,如果没有通过,则会重定向返回到loginurl 3.BasicHttpAuthenticationFilter:通过此filter修饰的url,要求用户已经通过认证,如果没有通过,则会要求通过Authorization 信息进行认证 4.LogoutFilter:通过此filter修饰的url,一旦收到url请求,则会立即调用subject进行退出,并重定向到redirectUrl 5.NoSessionCreationFilter:通过此filter修饰的url,不会创建任何会话 6.PermissionAuthorizationFilter:权限拦截器,验证用户是否具有相关权限 7.PortFilter:端口拦截器,不是通过制定端口访问url,将自动将端口重定向到指定端口 8.HttpMethodPermissionFilter:rest风格拦截器,配置rest的访问方式 9.RolesAuthorizationFilter:角色拦截器,未登陆,将跳转到loginurl,未授权,将跳转到unauthorizedUrl 10.SslFilter:HTTPS拦截器,需要以HTTPS的方式进行访问 11.UserFilter:用户拦截器,需要用户已经认证,或已经remember me

         Subject:                  表示当前操作的主体用户,是一个抽象的概念,Subject可以进行登录、退出、权限判断等动作,通常一个subject与一个线程进行关联。

         Realm:                 表示验证的数据源,存储用户的安全数据,可以进行用户名和密码的匹配,及用户权限查询。


3.Shiro配置方法


shiro 配置方法:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="" xmlns:xsi=""xmlns:util=""xsi:schemaLocation="://www.springframework.org/schema/beans/spring-beans-4.0.xsd .xsd://www.springframework.org/schema/aop/spring-aop-4.0.xsd://www.springframework.org/schema/context/spring-context-4.0.xsd://www.springframework.org/schema/tx/spring-tx-4.0.xsd"><description>Apache Shiro Security Configuration</description><!-- Realm实现 --><bean id="userRealm" class="com.ttyc.mammon.service.shiro.UserRealm"><property name="cachingEnabled" value="false"/></bean><!-- 会话ID生成器 --><bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/><!-- 会话Cookie模板 --><bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-arg value="sid"/><property name="domain" value=".ttyongche.com"/><property name="path" value="/"/><property name="httpOnly" value="false"/><property name="maxAge" value="-1"/></bean><!-- 会话DAO --><bean id="sessionDAO" class="org.crazycake.shiro.RedisSessionDAO"><property name="sessionIdGenerator" ref="sessionIdGenerator"/><property name="redisManager" ref="redisManager"/></bean><!-- 会话管理器 --><bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"><property name="globalSessionTimeout" value="1800000"/><property name="deleteInvalidSessions" value="true"/><property name="sessionDAO" ref="sessionDAO"/><property name="sessionIdCookieEnabled" value="true"/><property name="sessionIdCookie" ref="sessionIdCookie"/></bean><!-- 安全管理器 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="userRealm"/><property name="sessionManager" ref="sessionManager"/><property name="cacheManager" ref="redisCacheManager"/></bean><!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --><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="authFilter" class="com.ttyc.mammon.controller.filter.AuthFilter"/><bean id="permissionFilter" class="com.ttyc.mammon.controller.filter.PermissionFilter"/><!-- Shiro的Web过滤器 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"/><property name="loginUrl" value="/login"/><property name="filters"><util:map><entry key="auth" value-ref="authFilter"/><entry key="perm" value-ref="permissionFilter"/></util:map></property><property name="filterChainDefinitions"><value>/** = auth</value></property></bean><!-- Shiro生命周期处理器--><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- cacheManager --><bean id="redisCacheManager" class="org.crazycake.shiro.RedisCacheManager"><property name="redisManager" ref="redisManager" /></bean><!-- shiro redisManager --><bean id="redisManager" class="com.ttyc.mammon.service.shiro.RedisManager"><property name="host" value="${redis.host}" /><property name="port" value="${redis.port}" /><property name="expire" value="${redis.expire}" /><property name="dataBase" value="${redis.database}" /></bean></beans>

   Pom依赖: <shiro.version>1.2.2</shiro.version> <shiro.redis.version>2.4.2.1-RELEASE</shiro.redis.version>
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.crazycake</groupId><artifactId>shiro-redis</artifactId><version>${shiro.redis.version}</version></dependency>


UserRealm: 继承AuthorizingRealm,重写doGetAuthorization和doGetAuthorication方法。
 
 
 
@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String username = (String)principals.getPrimaryPrincipal();SysUser user = getUserByName(username);SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();SysRole sysRole = sysRolePermService.getSysRoleByUserId(user.getId());addRole(authorizationInfo,sysRole);List<SysPermission> sysPermissions = sysRolePermService.getSysPermissionByUserId(user.getId());addPermissions(authorizationInfo,sysPermissions);return authorizationInfo;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username = (String)token.getPrincipal();SysUser user = getUserByName(username);//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现if (user != null){return new SimpleAuthenticationInfo(user.getUserName(),"", getName());}return null;}


AuthFilter: AuthFilter继承AccessControllerFilter,需要重写isAccessAllowed和onAccessDenied方法
@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {HttpServletRequest httpRequest = (HttpServletRequest)request;HttpServletResponse httpResponse = (HttpServletResponse)response;//支持跨域supportCrossDomain(httpResponse);// 对外API,通过Service-Token进行认证String url = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());if (url.startsWith(HTTP_API_URL)) {if (validateSign(httpRequest.getHeader("Service-Token"))) {return true;}else {return false;}}//运营后台通过cookie,token,sid进行认证Subject currentSubject = SecurityUtils.getSubject();if (! currentSubject.isAuthenticated()){SysUser sysTokenUser = loginAuthService.validTokenAuth((HttpServletRequest) request);SysUser sysCookieUser = loginAuthService.validCookieAuth((HttpServletRequest) request);if (sysTokenUser == null && sysCookieUser == null){return false;}SysUser sysUser = null;if (sysTokenUser != null){sysUser = sysTokenUser;}else {sysUser = sysCookieUser;}UsernamePasswordToken token = new UsernamePasswordToken(sysUser.getUserName(),"");currentSubject.login(token);Session session = currentSubject.getSession();session.setAttribute("LoginUser",sysUser);}//在request里设置登录用户SysUser currentUser = (SysUser) currentSubject.getSession().getAttribute("LoginUser");request.setAttribute("loginId", currentUser.getId());return true;}@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {response.setContentType("application/json; charset=utf-8");response.getWriter().write(json);return false;}



RedisManager: shiro原生不支持redis,只支持ehcache,ehcache只能单机缓存,不适合于大型集群应用。第三方crazycake支持shiro使用redis缓存,配置方式如下:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;import java.util.Set;public class RedisManager extends org.crazycake.shiro.RedisManager {private String host = "127.0.0.1";private int port = 6379;// 0 - never expireprivate int expire = 0;// timeout for jedis try to connect to redis server, not expire time! In// millisecondsprivate int timeout = 0;private String password = "";private int dataBase;private static JedisPool jedisPool = null;public RedisManager() {}/*** 初始化方法*/public void init() {if (jedisPool == null) {if (password != null && "".equals(password.trim())) {password = null;}jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password, dataBase);}}/*** get value from redis* * @param key* @return*/public byte[] get(byte[] key) {byte[] value = null;Jedis jedis = jedisPool.getResource();try {value = jedis.get(key);} finally {jedis.close();}return value;}/*** set* * @param key* @param value* @return*/public byte[] set(byte[] key, byte[] value) {Jedis jedis = jedisPool.getResource();try {jedis.set(key, value);if (this.expire != 0) {jedis.expire(key, this.expire);}} finally {jedis.close();}return value;}/*** set* * @param key* @param value* @param expire* @return*/public byte[] set(byte[] key, byte[] value, int expire) {Jedis jedis = jedisPool.getResource();try {jedis.set(key, value);if (expire != 0) {jedis.expire(key, expire);}} finally {jedis.close();}return value;}/*** del* * @param key*/public void del(byte[] key) {Jedis jedis = jedisPool.getResource();try {jedis.del(key);} finally {jedis.close();}}/*** flush*/public void flushDB() {Jedis jedis = jedisPool.getResource();try {jedis.flushDB();} finally {jedis.close();}}/*** size*/public Long dbSize() {Long dbSize = 0L;Jedis jedis = jedisPool.getResource();try {dbSize = jedis.dbSize();} finally {jedis.close();}return dbSize;}/*** keys* * @param pattern* @return*/public Set<byte[]> keys(String pattern) {Set<byte[]> keys = null;Jedis jedis = jedisPool.getResource();try {keys = jedis.keys(pattern.getBytes());} finally {jedis.close();}return keys;}public String getHost() {return host;}public void setHost(String host) {this.host = host;}public int getPort() {return port;}public void setPort(int port) {this.port = port;}public int getExpire() {return expire;}public void setExpire(int expire) {this.expire = expire;}public int getTimeout() {return timeout;}public void setTimeout(int timeout) {this.timeout = timeout;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getDataBase() {return dataBase;}public void setDataBase(int dataBase) {this.dataBase = dataBase;}}



更多推荐

Shiro系统权限管理、及原理剖析

本文发布于:2023-06-18 23:16:05,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/777195.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:权限   原理   系统   Shiro

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!