登录认证
一、添加pom依赖
<!-- Shiro -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
二、登录拦截,如果没有登录,跳转到登录页面
1.在web.xml当中配置过滤器拦截所有请求,进行处理
<!-- 拦截到所有请求,使用spring一个bean来进行处理 -->
<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>
2.在Spring当中配置shiro过滤器和安全管理器
<!-- 配置shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<!-- 配置shiro过滤器pattern -->
<property name="filterChainDefinitions">
<value>
/static/** = anon <!-- 不需要登录验证 -->
/login.jsp = anon <!-- 不需要登录验证 -->
/**=authc <!-- 除指定请求外,其它所有的请求都需要身份验证 -->
</value>
</property>
</bean>
<!-- 配置shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"></bean>
三、登录认证
1.在Shiro过滤器中配置登录认证的路径
<!--
其他请求会判断当前有没有认证过
默认情况下没有认证,会跳转到login.jsp
配置了loginUrl,如果没有认证的话,就会执行对应的login请求
loginUrl:如果发现请求是loginUrl的值,会去做认证
配置登录认证的路径
-->
<property name="loginUrl" value="/login" />
2.创建登录Realm,创建一个类继承AuthorizingRealm
public class EmployeeRealm extends AuthorizingRealm {
@Autowired
private EmployeeService employeeService;
// 认证
@Override // 会自动把username和password封装到token里
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取身份信息
String username = (String) token.getPrincipal();
// 到数据库中查询有没有当前用户
Employee employee = employeeService.getEmployeeWithUsername(username);
if(employee == null){
return null;
}
// 认证
// 参数:主体、正确的密码、盐、当前realm名称
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
employee,
employee.getPassword(),
ByteSource.Util.bytes(employee.getUsername()),
this.getName()
);
return info;
}
// 授权
// 1.发现访问路径的方法上面有授权的注解,就会调用这个方法
// 2.页面当中有授权的标签,也会调用这个方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
}
}
3.配置Realm数据源
<!-- 自定义Realm -->
<bean id="employeeRealm" class="pers.liuchengyin.web.realm.EmployeeRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<!-- 配置shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 注入realm -->
<property name="realm" ref="employeeRealm"></property>
<!-- 注入缓存器 -->
<property name="cacheManager" ref="ehCache"/>
</bean>
4.表单发送登录请求
<script>
$(function () {
$("#loginBtn").click(function () {
// Ajax发送的请求,没有办法跳转服务当中的请求,只能通过浏览器当中来跳转
// 发送请求,做登录认证
$.post("/login",$("form").serialize(),function (data) {
// 把data,json格式的字符串转成json 数据
data = $.parseJSON(data);
if (data.success){
// 跳转到首页
window.location.href = "/index.jsp"
} else {
alert(data.msg);
}
});
});
});
</script>
5. 创建表单认证过滤器
public class MyFormFilter extends FormAuthenticationFilter {
// 认证成功调用
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
// 响应给浏览器
response.setCharacterEncoding("utf-8");
AjaxRes ajaxRes = new AjaxRes();
ajaxRes.setMsg("登陆成功");
ajaxRes.setSuccess(true);
// 把对象转成Json格式的字符串
String jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
response.getWriter().print(jsonString);
return false;
}
// 认证失败调用
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
// 响应给浏览器
AjaxRes ajaxRes = new AjaxRes();
ajaxRes.setSuccess(false);
if(e != null){
// 获取异常的名称
String name = e.getClass().getName();
if(name.equals(UnknownAccountException.class.getName())){
// 没有这个账号
ajaxRes.setMsg("账号不正确");
}else if(name.equals(IncorrectCredentialsException.class.getName())){
// 密码错误
ajaxRes.setMsg("密码不正确");
}else{
// 未知异常
ajaxRes.setMsg("未知错误");
}
}
try {
String jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
response.setCharacterEncoding("utf-8");
response.getWriter().print(jsonString);
} catch (IOException e1) {
e1.printStackTrace();
}
return false;
}
}
6.重新配置过滤器
<!-- 自定义的过滤器 -->
<bean id="myFormFilter" class="pers.liuchengyin.web.filter.MyFormFilter"/>
<!-- 配置shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 配置表单监听的过滤器 -->
<property name="filters">
<map>
<entry key="authc" value-ref="myFormFilter"></entry>
</map>
</property>
需要注意的是,Ajax发送的请求没有办法跳转服务当中的请求,只能通过浏览器自己来跳转。