项目框架:Spring + SpringMvc + Shiro + Mybatis + Redis
本章的源码地址:https://download.csdn.net/download/baidu_24352355/10476943
Shiro认证与授权的在Web中实现
第一步:添加依赖
<!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency>
第二步:配置web.xml
<!-- shiro 过滤器 start --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <!-- 设置true由servlet容器控制filter的生命周期 --> <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> <!-- shiro 过滤器 end --> |
第三步:自定义Realm继承AuthorizingRealm,重写AuthorizationInfo(授权)和AuthenticationInfo(认证)
<?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="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"></property> <property name="loginUrl" value="login.jsp"></property><!-- 没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面 --> <property name="unauthorizedUrl" value="error.jsp"></property><!-- 没有权限默认跳转的页面 --> <property name="filterChainDefinitions"> <value><!-- 自上到下 --><!-- anon:表示可以匿名使用。 authc:表示需要认证(登录)才能使用,没有参数. roles["admin,guest"],每个参数通过才算通过,user表示必须存在用户 --> /login.jsp = anon /subLogin = anon /testRoles = roles["admin"] /testRoles1 = rolesOr["admin","admin1"] /testPerms = perms["user:delete"] /testPerms1 = perms["user:delete","user:updata"] /* = authc </value> </property> <property name="filters"> <map> <entry key="rolesOr" value-ref="rolesOrFilter" /> </map> </property> </bean> <!-- 自定义权限filter --> <bean id="rolesOrFilter" class="com.shiro.filter.RolesOrFilter" /> <!-- 创建SecurityManager对象 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="realm" /> <property name="sessionManager" ref="sessionManager" /> <property name="cacheManager" ref="cacheManager" /> <property name="rememberMeManager" ref="cookieRememberMeManager" /> </bean> <!-- 自定义Realm --> <bean id="realm" class="com.shiro.realm.CustomRealm"> <property name="credentialsMatcher" ref="credentialsMatcher" ></property> </bean> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5" /> <property name="hashIterations" value="1" /> </bean> <!-- 自定义SessionManager --> <bean class="com.shiro.session.CustomSessionManager" id="sessionManager"> <property name="sessionDAO" ref="redisSessionDao"></property> </bean> <bean class="com.shiro.session.RedisSessionDao" id="redisSessionDao"></bean> <bean class="com.shiro.cache.RedisCacheManager" id="cacheManager"></bean> <!-- 自动登录 --> <bean class="org.apache.shiro.web.mgt.CookieRememberMeManager" id="cookieRememberMeManager"> <property name="cookie" ref="cookie"></property> </bean> <bean class="org.apache.shiro.web.servlet.SimpleCookie" id="cookie"> <constructor-arg name="name" value="rememberMe" /> <property name="maxAge" value="20000000" /> </bean> </beans>
一些属性的意义:
securityManager: 这个属性是必须的。
loginUrl: 没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
successUrl: 登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。
unauthorizedUrl: 没有权限默认跳转的页面。
Shiro中默认的过滤器:
过滤器名称 | 过滤器类 | 描述 |
---|---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter | 匿名过滤器 |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter | 如果继续操作,需要做对应的表单验证否则不能通过 |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter | 基本http验证过滤,如果不通过,跳转屋登录页面 |
logout | org.apache.shiro.web.filter.authc.LogoutFilter | 登录退出过滤器 |
noSessionCreation | org.apache.shiro.web.filter.session.NoSessionCreationFilter | 没有session创建过滤器 |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter | 权限过滤器 |
port | org.apache.shiro.web.filter.authz.PortFilter | 端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面 |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter | http方法过滤器,可以指定如post不能进行访问等 |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter | 角色过滤器,判断当前用户是否指定角色 |
ssl | org.apache.shiro.web.filter.authz.SslFilter | 请求需要通过ssl,如果不是跳转回登录页 |
user | org.apache.shiro.web.filter.authc.UserFilter | 如果访问一个已知用户,比如记住我功能,走这个过滤器 |
第五步:在spring-mvc.xml中配置权限的控制 异常的跳转
<!-- 保证 Shiro内部生命周期 --> <bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean> <!-- 开启Shiro授权生效 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
第六步:在controller中测试使用的验证登录
@RequestMapping( value="/subLogin", method= RequestMethod.POST, produces="application/json;charset=utf-8") @ResponseBody public String subLogin(User user) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); try { token.setRememberMe(user.isRememberMe()); subject.login(token); } catch (Exception e) { return e.getMessage(); } // 编码方式判断是否具有管理员身份 if (subject.hasRole("admin")) { return "有admin权限"; } return "无admin权限"; }
会话管理SessionManager
这里主要是结合了redis进行Sesssion的管理,自定义了RedisSessionDao
<!-- 自定义SessionManager -->
<bean class="com.shiro.session.CustomSessionManager" id="sessionManager">
<property name="sessionDAO" ref="redisSessionDao"></property>
</bean>
<bean class="com.shiro.session.RedisSessionDao" id="redisSessionDao"></bean>
自定义CustomSessionManager
/** * @author Luke * @date 2018/6/11. */ public class CustomSessionManager extends DefaultWebSessionManager { @Override protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { Serializable sessionId = getSessionId(sessionKey); //获取request ServletRequest request = null; if (sessionKey instanceof WebSessionKey) { request = ((WebSessionKey) sessionKey).getServletRequest(); } //若request不为空,并且sessionID不为空,则从request中获取session if (request != null && sessionId != null) { Session session = (Session) request.getAttribute(sessionId.toString()); //获取到的session不为空,则返回 if (session != null) { return session; } } //否则从redisSessionDao中获取session Session session = super.retrieveSession(sessionKey); //若获取的session不为空,则设值到request的作用域中 if (request != null && sessionId != null) { request.setAttribute(sessionId.toString(), session); } return session; } }
缓存管理CacheManager,也是结合Redis,从redis中获取缓存数据,提高性能
<bean class="com.shiro.cache.RedisCacheManager" id="cacheManager"></bean> |
public class RedisCacheManager implements CacheManager { @Autowired private RedisCache redisCache; @Override public <K, V> Cache<K, V> getCache(String s) throws CacheException { return redisCache; } } |
只贴出部分源码,详细的请下载源码运行,内含sql脚本(resources/shiro.sql)
更多博客请查看个人博客:https://blog.luke-lu.cn