Shiro教程之三自定义Realm认证和授权(结合数据库) [数据库教程]

database

Shiro默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。

1,Realm接口 

 

 

最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm

 

2,数据表设计

 

 

permission 菜单和权限表

role 角色表

role_permission 角色和权限的关系表

user 用户表

user_role用户和角色之间的关系表

 

 

3,实现步骤

1,创建shiro_realm的maven项目

web.xml文件过滤器配置:

<!-- Shiro filter start -->

<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>

<!-- 下面这个参数表示,applicationContext.xml(Shiro过滤器链)的名字,如果省略,配置器链名默认就是过滤器名字-->

<init-param>

<param-name>targetBeanName</param-name>

<param-value>shiroFilter</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>shiroFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<!-- Shiro filter end -->

 

applicationContext.xml设置

<!-- 10. Shiro认证权限配置-->

<!-- ================ Shiro start ================ -->

<!-- (1).声明凭证匹配器(密码加密用)-->

<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">

<!--注入算法-->

<property name="hashAlgorithmName" value="md5"></property>

<!--注入散列次数-->

<property name="hashIterations" value="1"></property>

</bean>

<!-- (2).配置Realm-->

<bean id="shiroReaml" class="com.cc8w.shiro.ShiroRealm">

<!--注入凭证匹配器-->

<property name="credentialsMatcher" ref="credentialsMatcher"></property>

</bean>

<!-- (3). 创建安全管理器-->

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

<!--注入reaml-->

<property name="realm" ref="shiroReaml"></property>

</bean>

<!-- (4). 配置过滤器链-->

<!-- Shiro 的Web过滤器 id必须和web.xml里面的shiroFilter的 targetBeanName的值一样 -->

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

<!--Shiro的核心安全接口,这个属性是必须的-->

<property name="securityManager" ref="securityManager"></property>

<!-- 要求登录时的链接(登录页面地址),非必须属性,属性会自动寻找web工程根目录下的"/login.jsp"页面-->

<property name="loginUrl" value="/login.jsp"></property>

<!-- Shiro 的Web过滤器 id必须和web.xml里面的shiroFilter的 targetBeanName的值一样 -->

<!--property name="successUrl" value="success.do"></property-->

<!-- 用户访问未对其授权的资源时,所显示的连接 -->

<property name="unauthorizedUrl" value="unauthorized.jsp"></property>

<!-- 过滤器链的定义,从上往下顺序执行,一般将/**放在最后-->

<property name="filterChainDefinitions">

<value>

<!-- /**=authc 所有url都必须认证通过才可以访问 -->

/index.jsp*=anon

/login/toLogin*=anon

/login/login*=anon

<!-- 如果访问/login/logout就是用Shiro注销session-->

/login/logout=logout

<!-- /** = anon所有url都可以匿名访问 -->

<!-- /** = authc -->

<!-- /*/* = authc -->

<!-- /** = authc所有url都不可以匿名访问 必须放到最后面 -->

/** = authc

</value>

</property>

</bean>

<!-- ================ Shiro end ================ -->

 

2,创建自定义realm (这个里面重写两个方法一个认证回调,一个授权回调)

package com.cc8w.shiro;

import com.cc8w.entity.UserActivePojo;

import com.cc8w.entity.UserPojo;

import com.cc8w.service.PermssionService;

import com.cc8w.service.RoleService;

import com.cc8w.service.UserService;

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.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 org.springframework.stereotype.Component;

import java.util.List;

/**

* Shiro默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。

* 最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm

*/

@Component

publicclass ShiroRealm extends AuthorizingRealm {

@Autowired

private UserService userService;

@Autowired

private RoleService roleService;

@Autowired

private PermssionService permssionService;

@Override

public String getName() {

returnthis.getClass().getSimpleName();

}

/*

* 登录信息和用户验证信息验证(non-Javadoc)

* @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)

*/

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

//1.从authenticationToken中获取身份信息,其实就是用户的登录名

String username = authenticationToken.getPrincipal().toString();

String password = authenticationToken.getCredentials().toString();

//2.根据用户名查询用户是否存在

UserPojo user=userService.queryUserByUserName(username);

System.out.println(user);

//返回null说明用户不存在

if(null!=user) {

//2.1根据用户名去查询用户拥有哪些角色

List<String> roles= roleService.queryRolesByUserName(user.getUserName());

System.out.println(roles);

//2.2根据用户名查询用户拥有哪些权限

List<String> permissions=permssionService.queryPermissionsByUserName(user.getUserName());

UserActivePojo activeUser=new UserActivePojo(user, roles, permissions);

//3.返回认证信息

/**

* 参数1 用户身份

* 参数2 用户在数据库里面存放的密码

* 参数3 当前类名

*/

SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(activeUser, user.getPassword(), this.getName());

//SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName)

return info;

}

returnnull;

}

/*

* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法(non-Javadoc)

* @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)

*/

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

//1.获得用户身份信息(PrincipalCollection有认证回调传来的第一个参数[activeUser])

UserActivePojo activeUser = (UserActivePojo) principalCollection.getPrimaryPrincipal();

System.out.println("doGetAuthorizationInfo");

//2.根据身份信息获取权限数据

SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();

//3.根据用户查询用户的角色 (其实认证方法一并查询出来了,保存在UserActivePojo)

List<String> roles = activeUser.getRoles();

if(null!=roles&&roles.size()>0) {

info.addRoles(roles);//添加角色

}

//4.根据用户查询用户的权限

List<String> permissions=activeUser.getPermissions();

if(null!=permissions&&permissions.size()>0) {

info.addStringPermissions(permissions);//添加权限

}

/**

* 总结:本来授权->查角色和权限都在本方法写(但是前端每查询一次权限,就会回调本方法一次,

* 所以直接查数据库,对数据库有压力),所以最后,

* 1.把查角色和权限方法写在了认证,然后封装成activeUser传递过来,这样Controller每次查权限,就不用查数据库了,直接在activeUser获取即可.

* 2.缓存应该也可以解决

*/

return info;

}

}

 

4,测试 (认证和授权)

package com.cc8w.test;

import com.cc8w.shiro.ShiroRealm;

import org.apache.log4j.Logger;

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.IncorrectCredentialsException;

import org.apache.shiro.authc.UnknownAccountException;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.authz.AuthorizationException;

import org.apache.shiro.authz.UnauthenticatedException;

import org.apache.shiro.authz.UnauthorizedException;

import org.apache.shiro.config.IniSecurityManagerFactory;

import org.apache.shiro.mgt.DefaultSecurityManager;

import org.apache.shiro.subject.Subject;

import org.apache.shiro.util.Factory;

import org.apache.shiro.mgt.SecurityManager;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Arrays;

/**

*

*/

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"classpath:applicationContext.xml"})

publicclass TestShiro {

privatestatic Logger logger = Logger.getLogger(TestShiro.class);

@Autowired

private ShiroRealm shiroRealm;

publicstaticvoid main(String[] args) {

TestShiro ts = new TestShiro();

ts.testAuth();

}

//三,登录测试(自定义Realm)

@Test

publicvoid testRealmLogin(){

//1.创建一个安全管理器的工厂

Factory<SecurityManager> factory = new IniSecurityManagerFactory();

//2.在工厂中获取安全管理器

DefaultSecurityManager securityManager = (DefaultSecurityManager) factory.getInstance();

//2.1 创建自定义Realm注入到安全管理器

//ShiroRealm shiroRealm = new ShiroRealm();//(SpringM在bean控制)

securityManager.setRealm(shiroRealm);

//3.将securityManager绑定到运行环境

SecurityUtils.setSecurityManager(securityManager);

//4.获取Subject对象(将要登录的用户)

Subject subject = SecurityUtils.getSubject();

//5.获取要登录用户的token,客户端传递过来的用户名和密码

String username = "zhangsan",password="123456";

UsernamePasswordToken token = new UsernamePasswordToken(username,password);

try{

//6.登陆(认证)

subject.login(token);

logger.info("登录了");

}catch (IncorrectCredentialsException e ){

logger.info("密码不正确");

logger.info(e);

}catch (UnknownAccountException e) {

System.out.println("没有这个帐号");

}catch (AuthenticationException e) {

e.printStackTrace();

}

//如果登录成功了,可以获取subject中各种状态了

Boolean isAuth = subject.isAuthenticated();

System.out.println("认证状态:" + isAuth);

// 7.授权 分为:基于角色授权 基于资源的授权

//7.1 基于角色授权

boolean permited = subject.hasRole("role1");

System.out.println("这是授权单个:"+permited);

boolean hasAllRoles = subject.hasAllRoles(Arrays.asList("role1","role2","role3"));

System.out.println("这个授权多个"+hasAllRoles);

// 使用check方法进行授权,如果授权不通过会抛出异常

// subject.checkRole("role13");

try {

subject.checkRole("roles1");

}catch (UnauthenticatedException e){

logger.info("没有这个角色");

//e.printStackTrace();

}catch (UnauthorizedException e){

logger.info("没有这个权限");

//e.printStackTrace();

}

//7.2 基于资源的授权

//isPermitted传入权限标识符

boolean isPermitted = subject.isPermitted("user:query");

System.out.println("单个权限判断:"+isPermitted);

boolean isPermittedAll = subject.isPermittedAll("user:query","user:adb","user:add");

System.out.println("多个权限判断"+isPermittedAll);

// 使用check方法进行授权,如果授权不通过会抛出异常

try {

subject.checkPermission("user:adb");

}catch (UnauthenticatedException e){

logger.info("没有这个角色");

//e.printStackTrace();

}catch (UnauthorizedException e){

logger.info("没有这个权限");

//e.printStackTrace();

}

}

//四,授权验证(自定义Realm)

publicvoid testRealmAuth(){

//其实授权也需要登陆(上面方法第7条之后:就是授权的验证)

}

}

 

 

前提是: 已经在service和mapper里面写了,角色和权限的查询!! 如下:

 

Shiro教程之三自定义Realm认证和授权(结合数据库)

以上是 Shiro教程之三自定义Realm认证和授权(结合数据库) [数据库教程] 的全部内容, 来源链接: utcz.com/z/535206.html

回到顶部