-
web.xml配置
<!-- 拦截到所有请求,由spring交给shiro处理 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <!-- 是否filter中的 init 和 destroy--> <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>
-
spring-shiro.xml配置
配置缓存管理器、凭证匹配器(散列算法,加盐,散列次数)、会话管理器、自定义Realm(可以注入凭证匹配器)、安全管理器(将自定义Realm注入)、自定义过滤器Filter、Shiro的Web过滤器(注入安全管理器,filterChainDefinitions,loginUrl等)<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--shiro核心过滤器--> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 如果配置了 loginUrl 没有认证 执行对应的login请求 --> <property name="loginUrl" value="/static/login.html"/> <!--配置安全管理器--> <property name="securityManager" ref="securityManager"></property> <!-- 配置shiro过滤器pattern --> <property name="filterChainDefinitions"> <value> /static/css/** = anon <!--静态文件不需要登录验证--> /static/images/** = anon /static/easyui/** = anon /static/json/** = anon /static/js/** = anon /static/login.html = anon /login = anon <!--登录请求不拦截--> /** = authc <!--除指定请求外,其它所有的请求都需要身份验证--> </value> </property> </bean> <!-- 配置shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!--注入realm--> <property name="realm" ref="employeeRealm"/> </bean> <!--自定义Realm--> <bean class="fei.web.shiro.realm.EmployeeRealm" id="employeeRealm"> <!--注入凭证管理器--> <property name="credentialsMatcher" ref="credentialsMatcher"/> </bean> <!--凭证管理器--> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <!--加密算法--> <property name="hashAlgorithmName" value="MD5"/> <!--加密次数--> <property name="hashIterations" value="3"/> </bean> </beans>
-
LoginController中执行
SecurityUtils.getSubject().login(token);
token是UsernamePasswordToken类或者其子类
token会被一直传,直到最后的自定义realm中,执行doGetAuthenticationInfo()
方法,查询数据库,如果存在返回SimpleAuthenticationInfo,自动进行密码比对,判断登陆成不成功/** * @function: 认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { LOG.info("来到了认证"); //获取身份信息 String username = (String) token.getPrincipal(); LOG.info("用户名:" + username); //根据用户名查询有没有当前用户 Employee employee = employeeService.getEmployeeByUserName(username); //没有查询到或者不是管理员,直接返回null if (employee == null) { return null; } if (employee.getAdmin() == false){ throw new NotAdminException("你不是管理员,不能访问"); } //定义加密的盐值,是ByteSource类型 ByteSource salt = ByteSource.Util.bytes(employee.getUsername()); LOG.info("密码明文:" + employee.getPassword()); /** * @function: 数据库密码加密(因为存的还是明文) * 参数:加密算法,密码(需要加密的字段),加密的盐值(通常为了区分各用户,使用用户主键),加密迭代次数 */ SimpleHash newpassword = new SimpleHash("MD5", employee.getPassword(), salt, 3); LOG.info("密码密文:" + newpassword); /** * 因为当前realm配置了凭证管理器,所以token中的密码会自动加密 * 就是将SimpleAuthenticationInfo的密码与token的密码进行匹配判断是否可以登录成功 * 参数: 主体,正确的密码,盐,当前realm名称 * */ SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(employee, newpassword, salt, this.getName()); return info; }
-
LoginController中捕获相关异常,返回json反馈信息给前端
@RequestMapping("/login") public ResultMessage userLogin(Employee employee){ ResultMessage message = new ResultMessage(); try { TokenManager.login(employee); LOG.info("登录成功"); return ResultMessage.succ(); }catch (UnknownAccountException e){ message.setResultCode(200); message.setResultMes("账户不存在"); LOG.warn("账户不存在"); return message; }catch (NotAdminException e){ /这个是我的自定义异常 message.setResultCode(200); message.setResultMes(e.getMessage()); LOG.warn(e.getMessage()); return message; } catch (IncorrectCredentialsException e){ message.setResultCode(200); message.setResultMes("密码错误"); LOG.warn("密码错误"); return message; }catch (Exception e){ message.setResultCode(500); message.setResultMes("服务器发生异常"); LOG.error(e.getMessage()); return message; } }
这就是我使用shiro进行登陆认证的流程及代码,如果有问题谢谢指正,要不点个赞吧,哈哈