1.在项目中要引入shiro的依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.2</version>
</dependency>
2.在web.xml文件中配置spring整和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>
3。在applicationContext-shiro.xml文件中配置shiro的过滤器工厂
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!--注册realm-->
<bean id="bosRealm" class="com.jujung.bos.realm.BosReam"></bean>
<!--安全管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm"></property>
</bean>
<!--注册退出过滤器-->
<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="/unauthorized.jsp"/>
</bean>
<!--配置shiro的过滤器工厂(id必须和web.xml文件中配置的filter的名字一样)-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--注入安全管理器-->
<property name="securityManager" ref="securityManager"></property>
<!--登录页面的url-->
<property name="loginUrl" value="/login.jsp"></property>
<!--成功页面的url-->
<property name="successUrl" value="/index.jsp"></property>
<!--权限不足时请求的url-->
<property name="unauthorizedUrl" value="/unauthorized.action"></property>
<!--注入退出过滤器-->
<property name="filters">
<map>
<entry key="logout" value-ref="logoutFilter" />
</map>
</property>
<!--注入url拦截规则-->
<property name="filterChainDefinitions">
<value>
<!--静态资源不要认证-->
/css/** = anon
/js/** = anon
/images/** = anon
/validatecode.jsp* = anon
/login.jsp = anon
<!--请求路径的权限-->
/loginController/login.action = anon
/loginController/logout.action = logout
<!--自定义权限,需要授权,也可以使用注解授权,这里只是用URL的方式示例-->
/staffController/list.action = perms["staff-list"]
<!--其他请求都需要认证-->
/* = authc
</value>
</property>
</bean>
</beans>
4.编写realm,并注给安全管理器
package com.jujung.bos.realm;
import com.jujung.bos.mapper.UserMapper;
import com.jujung.bos.pojo.User;
import com.jujung.bos.pojo.UserExample;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @author Jujung_Zheng
* @create 2019-01-09 17:06
*/
public class BosReam extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证方法
* @param authenticationToken 认证信息
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.根据用户名查询数据库中的密码
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String username = token.getUsername();
//根据名字查询用户
UserExample example = new UserExample();
example.createCriteria().andUsernameEqualTo(username);
List<User> users = userMapper.selectByExample(example);
User user = null;
if(users != null && users.size() > 0){
user = users.get(0);
}
//2.框架负责比对数据库中的密码和页面输入的密码是否一致
//第一个参数数据库查出的用户,在Controller可以通过subject对象获得
//第二个参数数据库查出的用户的密码
//第三个参数当前ream的类名
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
//把认证信息返回给安全管理器,框架去负责密码的比对
return authenticationInfo;
}
}
5.在longinController中编写登录验证的逻辑,退出登录的handler不用写,只要让/ogout.action进入logout拦截器即可,shiro会自动清空session并跳转到"/"路径。
@RequestMapping("/loginController/login.action")
public String login(HttpSession session,String username, String password, String checkcode, Model model) throws Exception{
/*====================================登录校验====================================*/
//非空校验
if(StringUtils.isBlank(username) || StringUtils.isBlank(password)){
model.addAttribute("errorMessage","用户名或密码不能为空");
return "forward:/login.jsp";
}
//从session中获取验证码,校验验证码
String key = (String)session.getAttribute("key");
if(!checkcode.equals(key)){
model.addAttribute("errorMessage","验证码错误");
return "forward:/login.jsp";
}
/*====================================登录认证====================================*/
//校验用户名和密码
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(username, MD5Utils.md5(password));
try{
/**
* longin()方法会去调用安全管理器,安全管理器会去的调用realm
* 如果认证没有通过将会抛异常
*/
subject.login(token);
}catch (UnknownAccountException e){
model.addAttribute("errorMessage","用户名不存在!!!");
e.printStackTrace();
return "forward:/login.jsp";
}catch (IncorrectCredentialsException e){
model.addAttribute("errorMessage","密码错误!!!");
e.printStackTrace();
return "forward:/login.jsp";
}
//在realm中放的是User这里取出来的就是User
User currentUser = (User)subject.getPrincipal();
//将登陆用户放到session中
session.setAttribute("currentUser",currentUser);
//跳转到主页
return "redirect:/index.jsp";
}
========================================到此为止 完成类登录认证===================================
第二步,在realm中完成授权
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//TODO 这里只是硬编码吗授权示例,后期要从 数据库查询当前登录用户,然后查询当前用户所有的授权授权给用户
//为用户授权
authorizationInfo.addStringPermission("staff-list");
return authorizationInfo;
}
使用 shiro框架主要完成:认证和授权两方面的内容。
认证:主要在realm中的doGetAuthenticationInfo方法中完成
授权:在realm中的doGetAuthorizationInfo方法中完成
授权之后还要进行权限控制,主要有三种权限控制方式
1.URL拦截权限控制(基于过滤器实现)
2.方法注解权限控制(基于代理技术实现)
使用注解之前一定要开启spring的CGLib代理,为标记shiro注解的类创建代理对象,这段配置一定要配置在springMVC.xml的配置文件中,否则注解不生效。
添加了在这个注解标记需要的权限之后,若是没有权限去访问handler会抛异常,controller层的异常需要自己配置一个全局异常处理器去捕获并处处理框架抛出的异常。
3.使用shiro标签进行权限控制,主要就是实现页面效果,没有权限的用户会隐藏一些页面元素。被shrio标签包围的页面元素name属性内是 需要的权限,若没有该权限会 隐藏该页面元素;