1
2、shiro介绍
2.1、什么是Shiro
它是一个安全框架,用于解决系统的认证和授权问题,同时提供了会话管理,数据加密机制。
3、Shiro使用步骤
3.1、导入jai包
Maven工程
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
Web工程
3.2配置过滤器 在web.xml
<!-- Shiro Security filter filter-name这个名字的值将来还会在spring中用到 -->
<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>
3.3 、产生代理类的方式(applicationContext.xml 下)
<!-- 告诉spring生成shiro代理子类时,采用cglib方式生成 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
3.4、Shiro 的配置文件 (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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置Spring整合shiro -->
<!-- 配置安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 自己编写一个realm域对象 -->
<property name="realm" ref="authRealm"/>
</bean>
<!-- 编写realm类 -->
<bean id="authRealm" class="cn.itcast.web.action.shiro.AuthRealm">
<!-- 注入密码比较器对象 -->
<property name="credentialsMatcher" ref="passwordMatcher"/>
</bean>
<!-- 密码比较器类 -->
<bean id="passwordMatcher" class="cn.itcast.web.action.shiro.PasswordMatcher"/>
<!-- Spring框架需要整合shiro安全框架 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 注入安全管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 登录页面 -->
<property name="loginUrl" value="/index.jsp"/>
<!-- 认证成功了,跳转的页面
<property name="successUrl" value=""/>
-->
<!-- 没有权限的跳转页面 -->
<property name="unauthorizedUrl" value="/index.jsp"/>
<!-- 定义访问的规则 -->
<property name="filterChainDefinitions">
<!-- /**代表下面的多级目录也过滤 -->
<value>
/index.jsp* = anon
/home* = anon
/sysadmin/login/login.jsp* = anon
/sysadmin/login/loginAction_logout* = anon
/login* = anon
/logout* = anon
/components/** = anon
/css/** = anon
/img/** = anon
/js/** = anon
/plugins/** = anon
/images/** = anon
/js/** = anon
/make/** = anon
/skin/** = anon
/stat/** = anon
/ufiles/** = anon
/validator/** = anon
/resource/** = anon
/** = authc
/*.* = authc
</value>
</property>
</bean>
下面这部分也是applicationContext-shiro.xml 中的数据 配置注解加上下面这部分
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 生成代理,通过代理进行控制 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true"/>
</bean>
<!-- 安全管理器 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
</beans>
3.5、在applicationContext.xml 中加载 shiro配置文件
<!-- 加载Shiro配置文件 -->
<import resource="classpath:applicationContext-shiro.xml"/>
3.6、要编写两个类 :
一是授权认证类:1、类名随意但建议以 Realm这个结尾,但必须继承 AuthorizingRealm类
2、有两个方法:一个是授权 一个是认证
public class AuthRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
@Override //授权方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("授权方法、、、、、、、、、、、、、、、");
return null;
}
@Override //认证方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("认证方法、、、、、、、、、、、、、、、");
UsernamePasswordToken token = (UsernamePasswordToken) arg0;
final String username = token.getUsername();
Specification<User> spec = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get("userName").as(String.class), username);
}
};
List<User> userList = userService.find(spec);
if(userList!=null && userList.size()>0){
User user = userList.get(0);
/*
SimpleAuthenticationInfo是AuthenticationInfo的实现类
参数1:主参数 用户名
参数1:密码
参数1:realm可能有多个 getName() 区分是哪个的Realm
*/
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
return null;
}
二是密码比较类:1、类名随意,但必须继承 AuthorizingRealm类
2、要重写方法
public class PasswordMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
// TODO Auto-generated method stub
// token:在LoginAction 方法中已经封装登录用户名和密码
// token 是一个接口 所以请转成实现类UsernamePassswordToken
UsernamePasswordToken uToken = (UsernamePasswordToken) token;
//获取登录时 的 用户名和密码
String username = uToken.getUsername();
char[] password = uToken.getPassword();
//将字符数组转码字符串
String strPassword = new String(password);
// 在将用户名和密码就行Md5 加密
// 将用户名和密码进行加密并加密二次
String upStri = new Md5Hash(username, password, 2).toString();
// 在取出从数据库中取出的密码进行比较
String sqlUPStr = (String) info.getCredentials();
return equals(upStri,sqlUPStr);
}
}
3.7、编写登录Action
1、登录方法
try {
// shiro 的工具
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// AuthenticationToken是接口不能只用 使用它的子类 令牌 ()
// UsernamePasswordToken
// 讲用户名和密码封装到token中
subject.login(token);
User user = (User) subject.getPrincipal();
//SysConstant.CURRENT_USER_INFO这是个工具类定义的常量
session.put(SysConstant.CURRENT_USER_INFO, user);
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
super.put("errorInfo","用户名或密码不正确!!!");
return "login";
}
2、退出方法
@Action("loginAction_logout")
public String logout() {
//SysConstant.CURRENT_USER_INFO这是个工具类定义的常量
session.remove(SysConstant.CURRENT_USER_INFO); // 删除session
SecurityUtils.getSubject().logout(); // 登出
return "logout";
}