自定义Realm
- 自定义类继承AuthorizingRealm
提供了两个方法,一个是授权doGetAuthorizationInfo,一个是身份认证 doGetAuthenticationInfo
/*自定义类继承AuthorizingRealm*/
public class MyRealm extends AuthorizingRealm{
/*授权*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//创建一个授权对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取并设置角色
Set<String> roles = setRoles();
authorizationInfo.setRoles(roles);
//获取并设置权限
Set<String> perms = setPerms();
authorizationInfo.setStringPermissions(perms);
return authorizationInfo;
}
//模拟数据库设置角色
private Set<String> setRoles(){
Set<String> roles = new HashSet<String>();
roles.add("admin");
return roles;
}
//模拟数据库设置权限
private Set<String> setPerms(){
Set<String> perms = new HashSet<String>();
perms.add("*");
perms.add("employee:save");
return perms;
}
/*
* 登录功能 返回null代表用户名不存在
* 密码交给shiro,会自动帮我们判断
*
* */
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//拿到用户密码 令牌 强转
UsernamePasswordToken token =(UsernamePasswordToken)authenticationToken;
//获取用户名
String username = token.getUsername();
//判断用户名是否存在
String password = findUsername(username);
if(password==null){
//如果用户名不存在就返回null
return null;
}
//设置盐值
ByteSource salt = ByteSource.Util.bytes("ok");
//判断密码是否正确
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,getName());
return authenticationInfo;
}
private String findUsername(String username){
if (username.equals("admin")){
return "3e8139cbebae8c69264cb26c8a5dfdcf";
}else if (username.equals("it")){
return "123456";
}
return null;
}
}
测试自定义类Realm
public class RealmTest {
@Test
public void test(){
//获取权限管理器对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//创建一个Relam
MyRealm relam = new MyRealm();
//创建一个凭证匹配器
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//设置匹配器算法
matcher.setHashAlgorithmName("MD5");
//设置迭代的次数
matcher.setHashIterations(10);
//设置凭证匹配器
relam.setCredentialsMatcher(matcher);
//将relam放在权限管理器中
securityManager.setRealm(relam);
//把管理器放在工具中
SecurityUtils.setSecurityManager(securityManager);
//拿到当前用户
Subject subject = SecurityUtils.getSubject();
//是否登录
System.out.println("是否登录"+subject.isAuthenticated());
//如果没登录就进行登录
if (!subject.isAuthenticated()){
//拿到令牌
UsernamePasswordToken token = null;
try {
token = new UsernamePasswordToken("admin","123456");
//登录
subject.login(token);
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
e.printStackTrace();
}catch (IncorrectCredentialsException e){
System.out.println("密码不正确");
e.printStackTrace();
}catch (AuthenticationException e){
System.out.println("未知错误");
e.printStackTrace();
}
//角色判断
System.out.println("是否是admin"+subject.hasRole("admin"));
System.out.println("是否是it"+subject.hasRole("it"));
//权限判断
System.out.println("是否是employee:save"+subject.isPermitted("employee:save"));
System.out.println("是否是employee:delete"+subject.isPermitted("employee:delete"));
System.out.println("是否是employee:update"+subject.isPermitted("employee:update"));
//是否登录
System.out.println("是否登录"+subject.isAuthenticated());
}
}
//加密密码
@Test
public void testHash(){
/*
* algorthmName 算法
* source 密码
* salt 盐值
* hashIterations 迭代次数
*
* e10adc3949ba59abbe56e057f20f883e
* 盐值 47fbb266bd4270ef4bc1fcf7e0e8a08a
* 盐值+10 3e8139cbebae8c69264cb26c8a5dfdcf
* */
SimpleHash hash = new SimpleHash("MD5", "123456","ok",10);
System.out.println(hash.toHex());
}
}
shiro和Spring集成
- 导包
<!-- shiro(权限框架)的支持包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.4.0</version>
<type>pom</type>
</dependency>
<!-- shiro与Spring的集成包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
- web.xml中配置代理过滤器
<!--shiro 过滤器 什么都不做
Delegating 委托给其他地方
Proxy 这个管理器只是代理,通过名字shiroFilter去找真正做事的
但是这个过滤器是不可缺的
-->
<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>
- 自定义类MyRealm
模拟数据库我们去获取里面的值,在application中需要配置
/*自定义类继承AuthorizingRealm*/
public class MyRealm extends AuthorizingRealm{
/*授权*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//创建一个授权对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取并设置角色
Set<String> roles = setRoles();
authorizationInfo.setRoles(roles);
//获取并设置权限
Set<String> perms = setPerms();
authorizationInfo.setStringPermissions(perms);
return authorizationInfo;
}
//模拟数据库设置角色
private Set<String> setRoles(){
Set<String> roles = new HashSet<String>();
roles.add("admin");
return roles;
}
//模拟数据库设置权限
private Set<String> setPerms(){
Set<String> perms = new HashSet<String>();
perms.add("employee:index");
return perms;
}
/*
* 登录功能 返回null代表用户名不存在
* 密码交给shiro,会自动帮我们判断
*
* */
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//拿到用户密码 令牌 强转
UsernamePasswordToken token =(UsernamePasswordToken)authenticationToken;
//获取用户名
String username = token.getUsername();
//判断用户名是否存在
String password = findUsername(username);
if(password==null){
//如果用户名不存在就返回null
return null;
}
//设置盐值
ByteSource salt = ByteSource.Util.bytes("ok");
//判断密码是否正确
/*
*第一个参数 username 登录成功后可以在任何地方拿的数据
*第二个参数 password 从数据库查询出来的密码
*第三个参数 salt 盐值
*第四个参数 当前realm的名字
*
* */
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,"myRealm");
return authenticationInfo;
}
private String findUsername(String username){
if (username.equals("admin")){
return "3e8139cbebae8c69264cb26c8a5dfdcf";
}else if (username.equals("it")){
return "123456";
}
return null;
}
}
- 自定义类工厂返回权限
1.返回的Map值是有顺序的;
2. 修改后要重启(热启动无效);
3.解决在xml中配置权限繁琐的问题,以后通过读取数据库内容来设置权限。
public class FilterChainDefinitionsMapFactory {
public Map<String,String> createMap(){
//返回权限数据
Map<String,String> map = new LinkedHashMap<>();
//添加不拦截的数据
map.put("/login","anon");
//添加权限拦截数据
map.put("/employee/index","perms[employee:index]");
map.put("/department/index","perms[department:index]");
//拦截所有
map.put("/**","authc");
return map;
}
}
- applicationContext-shiro.xml的配置
需要在 applicationContext.xml 中引入它 < import
resource="classpath: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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--shiro的核心管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="MyRealm"/>
</bean>
<!-- 创建相应的Realm(拿权限数据的对象)
AisellRealm realm = new AisellRealm();-->
<bean id="MyRealm" class="cn.itsource.aisell.web.shiro.MyRealm">
<!--名称-->
<property name="name" value="MyRealm"/>
<!--凭证匹配器 realm.setCredentialsMatcher(..) -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--加密算法-->
<property name="hashAlgorithmName" value="MD5"/>
<!--迭代次数-->
<property name="hashIterations" value="10"/>
</bean>
</property>
</bean>
<!--可以支持注解权限控制-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!--
shiro真实的权限过滤器(这个名字必需和shiro过滤器的名字一致)
-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--引入权限管理器-->
<property name="securityManager" ref="securityManager"/>
<!--没有登录就会进入这个路径-->
<property name="loginUrl" value="/s/login.jsp"/>
<!--登录成功后进入页面-->
<property name="successUrl" value="/s/success.jsp"/>
<!--没有权限进入的页面-->
<property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
<!--
filterChainDefinitions:过滤器描述(有顺序)
anon:不登录也可以访问(游客可以访问的页面)
authc:必需登录才可以访问
-->
<!-- <property name="filterChainDefinitions">
<value>
/login= anon
/s/permission.jsp = perms[employee:index]
/department/index = perms[department:index]
/** = authc
</value>
</property>-->
<property name="filterChainDefinitionMap" ref="filterChainDefinitionsMap"></property>
</bean>
<!--把工厂中的方法返回值也变成一个bean-->
<bean id="filterChainDefinitionsMap" factory-bean="filterChainDefinitionsMapFactory" factory-method="createMap"/>
<!--创建工厂bean-->
<bean id="filterChainDefinitionsMapFactory" class="cn.itsource.aisell.web.shiro.FilterChainDefinitionsMapFactory"/>
</beans>