近期学习了关于shiro框架的使用,主要用来认证登陆和权限分配。
需求
认证登陆的实现。
说明
前提条件:一个可以运行的SSM的项目;
数据库:mysql;
运行流程
应用程序 — Subject — SecurityManager — Realm — 安全数据。
具体实现
1. 配置web.xml
<filter>
<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>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 配置applicationContext.xml
一句话,引入shiro配置:
<import resource="applicationContext-shiro.xml"></import>
3. 配置applicationContext-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="true">
<!-- shiro的核心配置: 配置shiroFileter id名必须与web.xml中的filtername保持一致 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/index" />
<property name="unauthorizedUrl" value="/unauthorized" />
<!-- shiro过滤器的具体配置 -->
<!-- anon-匿名访问,authc-需要认证 -->
<property name="filterChainDefinitions">
<value>
/index = authc
/login = anon
/logout = logout
/common/**= anon
/** = authc
</value>
</property>
</bean>
<!-- 配置安全管理器securityManager, 缓存技术: 缓存管理 realm:负责获取处理数据 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroRealm" />
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- 項目自定义的Realm,从数据库中获取用户的安全数据 -->
<bean id="shiroRealm" class="com.yzpt.config.ShiroConfig">
<!-- 配置缓存管理器 -->
<property name="cacheManager" ref="cacheManager" />
<!-- 配置加密器 -->
<!-- <property name="credentialsMatcher">
<bean
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property> 加密算法的名称
<property name="hashIterations" value="1024"></property> 配置加密的次数
</bean>
</property> -->
</bean>
<!-- 用户授权信息Cache -->
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
</beans>
PS:上面的shiro配置中,关于权限分配的那块已经配置完成,这边暂时就不多说明了。
4. 代码实现
ShiroConfig.java的部分代码:
// 登陆认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken currentUser = (UsernamePasswordToken) token;
String username = currentUser.getUsername();
// 根据用户名查询用户信息
User user = userMapper.getUserByUsername(username);
if (user == null) {
// 用户名不存在
// 说明:如果返回null,说明用户不存在,报用户名不存在的异常
return null;
}
// 用户名存在
// 当返回用户密码时,securityManage安全管理器,自动比较返回密码和用户输入的密码是否一致
// 如果密码一致,则登陆成功,如果密码不一致,则报密码错误异常
// 参数说明:1.查询出来的用户信息 2.用户密码 3.user.getCredentialsSalt()//salt=username+salt(暂时没用到) 4.realm name
AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
return info;
}
5. 调用
LoginController.java的部分代码:
/**
* Description: 登陆认证
*
* @param request
* @param response
* @return
*
*/
@RequestMapping(value = "/login", produces="text/html;charset=UTF-8;",method=RequestMethod.POST)
@ResponseBody
public String login(HttpServletRequest request, HttpServletResponse response) {
// 定义返回结果
String result = "";
// 获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username == null || "".equals(username)) {
result = "用户名为空!";
logger.info("用户名为空!");
} else {
// 使用 shiro 登录验证
// 1 认证的核心组件:获取 Subject 对象
Subject subject = SecurityUtils.getSubject();
// 2 将登陆表单封装成 token 对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
// 3 让 shiro 框架进行登录验证:
subject.login(token);
result = "success";
} catch (IncorrectCredentialsException e) {
result = "用户名或密码错误!";
logger.info(result);
} catch (LockedAccountException e) {
result = "帐号已被锁定!";
logger.info(result);
} catch (DisabledAccountException e) {
result = "帐号已被禁用!";
logger.info(result);
} catch (ExpiredCredentialsException e) {
result = "帐号已过期!";
logger.info(result);
} catch (UnknownAccountException e) {
result = "用户不存在!";
logger.info(result);
} catch (UnauthorizedException e) {
result = "您没有得到相应的授权!";
logger.info(result);
}
}
return result;
}
PS:如果想要完整的走一下这个流程,可以在代码实现的AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)方法中打个断点,在登陆过程中,subject.login(token)代码执行后进入认证登陆。