使用ssm框架,xml和注解组合的方式搭建shiro框架,初学只搭建最简单的框架,提供认证,授权,密码管理等基本用法
一、搭建一个ssm项目,不需要连接数据库,这里用代码写死,可以正常访问即可,在这个项目基础上搭建shiro
二、导入shiro依赖
<!-- shiro 依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
三、web.xml中加入shiro的过滤
<!-- shiro安全过滤器 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>
四、写一个spring的配置文件,根据这个配置文件,完善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: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">
<description>Shiro的配置</description>
<!-- 自定义权限认证:类1,shiro的核心类,这个类需要注入两个属性
属性1:loginService,这是用于登录的服务的具体实现类,由我们自身业务提供;
属性2:credentialsMatcher,这个属性不可变,具体的引用类由我们自己写,
写的这个引用类需要继承SimpleCredentialsMatcher这个类,并且实现
doCredentialsMatch()这个方法
-->
<bean id="authRealm" class="com.enjoy.shiro.AuthRealm">
<!--登录服务:类2--><!--注解注入-->
<!--<property name="loginService" ref="loginService"></property>-->
<!-- 自定义的类,需继承其他类,将这个类通过注解方式注入到spring中,在这里被引用 :类3-->
<property name="credentialsMatcher" ref="passwordMatcher"/>
</bean>
<!-- SecurityManager配置,安全管理配置,引用自定义的authRealm -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<property name="realm" ref="authRealm"/><!-- 引用自定义的realm -->
</bean>
<!-- filter-name这个名字的值来自于web.xml中filter的名字,shiro核心控制器,默认加载其他过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--登录页面 -->
<property name="loginUrl" value="/index"></property>
<!-- 登录成功后 -->
<property name="successUrl" value="/index2"></property>
<property name="filterChainDefinitions">
<!-- /**代表下面的多级目录也过滤 -->
<value>
/login = anon
/logout = anon
/css/** = anon
/images/** = anon
/js/** = anon
/skin/** = anon
/resource/** = anon
/** = authc
/*.* = authc
</value>
</property>
</bean>
<!--下面这三个类是固定写法,不需要修改-->
<!-- 保证实现了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>
五、根据第四部的配置文件,将我们自定义的类写好,一共有三个类需要我们实现
(1)登录服务类—loginService,这个类根据自己实际业务写就可以,我这里没查数据库,写死了用户名,只要输入这个用户名就代表查询到该用户,可以获取该用户的详细信息。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.enjoy.domain.User;
@Service
public class LoginService {
@Autowired
private User user;
public int login(String username,String password) {
if("zh".equals(username)) {
return 1;
}
return 0;
}
public User getUser() {
return user;
}
}
(2)自定义权限认证类—AuthRealm,继承AuthorizingRealm这个类,重写认证授权方法
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.enjoy.domain.User;
import com.enjoy.service.LoginService;
public class AuthRealm extends AuthorizingRealm{
@Autowired
private LoginService loginService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("调用授权方法");
//获取当前用户,拿到用户详细信息
User user = (User)pc.getPrimaryPrincipal();
//获取授权类,添加授权信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("系统首页");
info.addStringPermission("系统");
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("调用认证方法");
//获取token,得到用户名和密码
UsernamePasswordToken token = (UsernamePasswordToken)arg0;
String username = token.getUsername();
String password = new String(token.getPassword());
int i = loginService.login(username, password);
//如果用户存在,则返回info,走密码对比,否则返回null,抛出异常
if(i ==1) {
User user = loginService.getUser();
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
return info;
}else {
return null;
}
}
}
(3)自定义密码比较算法类—CustomCredentialsMatcher,需要继承SimpleCredentialsMatcher类,重写doCredentialsMatch方法
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.stereotype.Component;
/**
*
* @author myPC
* 自定义加密算法
*/
@Component(value="passwordMatcher")
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{
@Override
/*
* 参数1:token,用户输入信息
* 参数2:info,数据库查出的信息
* 返回值:布尔值
*/
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
//比较用户输入的密码和数据库密码是否一致
System.out.println("调用自定义密码对比方法");
//获取用户输入的密码
char[] password = ((UsernamePasswordToken)token).getPassword();
String pw = new String(password);
String md5 = MD5Util.getMD5(pw, ((UsernamePasswordToken)token).getUsername(), 2);
//获取数据库存的密码
Object obj = info.getCredentials();
return equals(md5,obj);
}
}
以上这三个类,有的是通过xml方式注入到spring中,有的是通过注解注入。需要搞清楚。
附MD5加密工具类
import org.apache.shiro.crypto.hash.Md5Hash;
public class MD5Util {
public static String getMD5(String arg0,String arg1,int arg2) {
//MD5加密
//参数1:要加密的字符串,参数2:混淆的字符串,参数3,哈希几次
Md5Hash hash = new Md5Hash(arg0,arg1,arg2);
return hash.toString();
}
}
六、调用shiro方式进项登录
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/")
public class IndexController {
@RequestMapping("login")
public String toLogin(String username,String password) {
//获得subject
Subject subject = SecurityUtils.getSubject();
//创建令牌,传入用户名和密码
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
//调用subject的login方法,传入令牌,如果没跑出异常,则进入index2方法,否则进入login
subject.login(token);
} catch (Exception e) {
System.out.println("未验证,请登录");
return "login";
}
return "index2";
}
七、启动项目,输入licalhost:8090/login
输入用户名和密码,zh/123
根据右面对应的页面name值为系统首页的有权限,显示标签,name值为系统1的没有授权,不显示
@RequiresPermissions({"系统首页"})
@RequestMapping("index4")
public String toIndex4() {
return "index4";
}
index4路径需要获得系统首页的授权才能访问。
八、总结。整个访问流程是通过web.xml进行拦截,在spring的配置中多级目录过滤进行授权,系统访问时,调用subject.login()方法,走认证方法,比对完密码后如果正确进行放行,如果在访问时需要权限认证,则在走授权方法,判断是否有权限,有权限就放行。