发表于: 2020-08-06 23:44:06
1 2036
学习shiro框架
导包
shiro-core-1.3.2.jar shiro-ehcache-1.3.2.jar shiro-quartz-1.3.2.jar shiro-spring-1.3.2.jar shiro-web-1.3.2.jar
在web.xml中配置Shiro的过滤器
与Spring集成:
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<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>
和SpringMVC框架类似,Shiro框架也需要在web.xml中配置一个过滤器。DelegatingFilterProxy
会自动到Spring容器中name为shiroFilter
的bean,并且将所有Filter的操作都委托给他管理。
这就要求在Spring配置中必须注入这样一个这样的Bean:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"></bean>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的安全管理器,所有关于安全的操作都会经过SecurityManager -->
<property name="securityManager" ref="securityManager"/>
<!-- 系统认证提交地址,如果用户退出即session丢失就会访问这个页面 -->
<property name="loginUrl" value="/login.jsp"/>
<!-- 权限验证失败跳转的页面,需要配合Spring的ExceptionHandler异常处理机制使用 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name="filters">
<util:map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
</util:map>
</property>
<!-- 自定义的过滤器链,从上向下执行,一般将`/**`放到最下面 -->
<property name="filterChainDefinitions">
<value>
<!-- 静态资源不拦截 -->
/static/** = anon
/lib/** = anon
/js/** = anon
<!-- 登录页面不拦截 -->
/login.jsp = anon
/login.do = anon
<!-- Shiro提供了退出登录的配置`logout`,会生成路径为`/logout`的请求地址,访问这个地址即会退出当前账户并清空缓存 -->
/logout = logout
<!-- user表示身份通过或通过记住我通过的用户都能访问系统 -->
/index.jsp = user
<!-- `/**`表示所有请求,表示访问该地址的用户是身份验证通过或RememberMe登录的都可以 -->
/** = user
</value>
</property>
</bean>
<!-- 基于Form表单的身份验证过滤器 -->
<bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<property name="usernameParam" value="username"/>
<property name="passwordParam" value="password"/>
<property name="loginUrl" value="/login.jsp"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
</bean>
<!-- Realm实现 -->
<bean id="userRealm" class="cn.tycoding.realm.UserRealm"></bean>
</bean>
身份认证的流程
如果用户为登录,将跳转到loginUrl进行登录,登录表单中,包含了两个主要参数:用户名username、密码password(这两个参数名称不是固定的,但是要和FormAuthenticationFilter表单过滤器的参数配置要对应)。
用户输入这两个用户名和密码后提交表单,通过绑定了SecurityManager的SecurityUtils得到Subject实例,然后获取身份验证的UsernamePasswordToken传入用户名和密码。
调用subject.login(token)进行登录,SecurityManager会委托Authenticator把相应的token传给Realm,从Realm中获取身份认证信息。
Realm可以是自己实现的Realm,Realm会根据传入的用户名和密码去数据库进行校验(提供Service层登录接口)。
Shiro从Realm中获取安全数据(如用户、身份、权限等),如果校验失败,就会抛出异常,登录失败;否则就登录成功。
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(
@RequestParam(value = "username", required = false) String username,
@RequestParam(value = "password", required = false) String password,
Model model) {
String error = null;
if (username != null && password != null) {
//初始化
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
//登录,即身份校验,由通过Spring注入的UserRealm会自动校验输入的用户名和密码在数据库中是否有对应的值
subject.login(token);
return "redirect:index.do";
}catch (Exception e){
e.printStackTrace();
error = "未知错误,错误信息:" + e.getMessage();
}
} else {
error = "请输入用户名和密码";
}
//登录失败,跳转到login页面,这里不做登录成功的处理,由
model.addAttribute("error", error);
return "login";
}
}
/**
* 身份校验
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.findByName(username);
if (user == null) {
throw new UnknownAccountException(); //没有找到账号
}
if (Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException(); //账号锁定
}
//交给AuthenticationRealm使用CredentialsMatcher进行密码匹配
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getUsername(), //用户名
user.getPassword(), //密码
getName() //realm name
);
return authenticationInfo;
}
}
明日计划 shiro实现加密解密 授权 整合进task5
评论