在Spring + SpringMVC + mybatis架构的项目基础上集成Shiro
Shiro使用五步走:
一、pom文件引入shiro依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.2.5</version> </dependency>
二、在Web.xml中配置shiroFilter
<!--shiro配置--> <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>
三、在Spring配置文件中引入shiro的配置文件spring-shiro.xml
<!--引入spring-shiro--> <import resource="spring-shiro.xml"/>
spring-shiro.xml文件的内容:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="login" /> <property name="successUrl" value="welcome" /> <property name="unauthorizedUrl" value="/login" /> <property name="filters"> <util:map> <entry key="authc" value-ref="formAuthenticationFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /static/** = anon /plugins/** = anon /login* = anon /logout = logout /** = authc /** = user </value> </property> </bean> <!--创建shiro的安全管理器的对象--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myShiroRealm" /> <!--声明会话管理器属性--> <!--<property name="sessionManager" ref="sessionManager"></property>--> <!--声明rememberMe--> <property name="rememberMeManager" ref="rememberMeManager"></property> </bean> <!-- 项目自定义的Realm --> <bean id="myShiroRealm" class="com.blueice.shiro.MyShiroRealm"> <property name="credentialsMatcher" ref="credentialsMatcher"/> <property name="cachingEnabled" value="false"/> </bean> <!-- 凭证匹配器(加密器) --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <!--<constructor-arg ref="shiroCacheManager" />--> <property name="hashAlgorithmName" value="md5" /> <property name="hashIterations" value="3" /> <!--storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码--> <property name="storedCredentialsHexEncoded" value="true" /> </bean> <!-- 基于表单认证的过滤器 --> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"/> <!-- 这是干啥的?? --> <!--<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>--> <!--记住我的配置--> <!--声明cookie对象--> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"></constructor-arg> <!--只有http的链接才能使用cookie--> <property name="httpOnly" value="true"></property> <!--cookie的失效时间30天,单位是秒--> <property name="maxAge" value="2592000"></property> </bean> <!--声明记住我的管理器对象--> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <property name="cookie" ref="rememberMeCookie"></property> </bean> </beans>
四、继承AuthorizingRealm,自定义授权和认证信息
package com.blueice.shiro; import com.blueice.entity.SysUser; import com.blueice.services.IndexService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import javax.annotation.Resource; import java.text.ParseException; import java.util.*; /** * @desctiption 实现自己的JDBC Realm * @author shaoz * @date 2020-08-17 14:12 */ public class MyShiroRealm extends AuthorizingRealm { @Resource(name = "indexService") private IndexService indexService; /** * 获取授权信息 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String userName = (String)principals.getPrimaryPrincipal(); // 用户权限列表 Set<String> permsSet = Collections.singleton("test"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setStringPermissions(permsSet); return authorizationInfo; } /** * 获取认证信息 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); SysUser user = null; if (username != null && !"".equals(username)) { user = indexService.selectUserInfoByUsername(username); } if (null == user) { // 没找到帐号 throw new UnknownAccountException(); } if (user.getStatus() == 0) { // 用户被停用 throw new LockedAccountException(); } ByteSource salt = ByteSource.Util.bytes(user.getUsername()); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), user.getPassword(), salt, getName()); return info; } public static void main(String[] args) throws ParseException { String hashAlgorithmName = "MD5"; String credentials = "123456"; int hashIterations = 3; ByteSource salt = ByteSource.Util.bytes("test"); Object obj = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); System.out.println(obj); } }
五、在controller层实现登录认证&退出登录
@RequestMapping(value="/login_login") @ResponseBody public String login_login(String username, String password, String isRememberMe) { String error = null; try { username = URLDecoder.decode(username, "UTF-8"); password = URLDecoder.decode(password, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println(username + password); // 先把账号密码传入shiro里面的UsernamePasswordToken对象里面 UsernamePasswordToken token = new UsernamePasswordToken(username, password); // 创建Subject对象 Subject subject = SecurityUtils.getSubject(); if ("1".equals(isRememberMe)) { token.setRememberMe(true); } // 调用subject.login()进行登录 try { subject.login(token); //SysUser sysUser = (SysUser) subject.getPrincipals(); } catch (UnknownAccountException e) { error = "用户名/密码错误"; } catch (IncorrectCredentialsException e) { error = "用户名/密码错误"; } catch (ExcessiveAttemptsException e) { // TODO: handle exception error = "登录失败多次,账户锁定10分钟"; } catch (AuthenticationException e) { // 其他错误,比如锁定,如果想单独处理请单独catch处理 error = "其他错误:" + e.getMessage(); } if (error != null) { // 出错了,返回登录页面 return error; } else { // 登录成功 return "success"; } /** * 退出登录 * @return */ @RequestMapping("/logout") public ModelAndView logout() { ModelAndView mv = new ModelAndView(); Subject subject = SecurityUtils.getSubject(); subject.logout(); mv.setViewName("login"); return mv; } }
shiro使用就是这么简单,原理:下次搞懂了再讲。。。