Shiro框架的配置

##一:什么是Shiro

认证和授权

1.官方首页: http://shiro.apache.org/

2.核心功能:

Authentication : 认证

Authorization : 授权

Session Management : 会话管理

Cryptography : 加密

 3.代码调用流程:

application code : 自己实现的代码

subject : 主题/ 主体(人),代表的就是当前用户

securitymannager : 最核心的对象,所有功能的实现都由安全管理器实现

realm : 安全数据桥.DAO,所有的和用户相关的权限身份数据

 

 

##二:实现后台系统认证:

1.整合shiro框架:

1.1 导入坐标:

<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-all</artifactId>
			<version>${shiro.version}</version>
</dependency>

1.2 配置web.xml

<!--
		Spring提供的,用于整合shiro框架的
		一定要写在Struts框架的前端控制器之前
		本filter创建的时候,需要注入一个对象,这个对象必须声明在applicationContext.xml中,
		而且这个对象的id必须和本filter的name保持一致
	-->
	<filter>
		<filter-name>shiroFilterFactoryBean</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilterFactoryBean</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

1.3 配置applicationContext.xml

	<!--
		工厂bean,初始化shiro框架提供的filter
	-->
	<bean id="shiroFilterFactoryBean" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 注入安全管理器 -->
		<property name="securityManager" ref="securityManager"></property>

		<!-- 登录页面的url,认证的页面 -->
		<property name="loginUrl" value="/login.html"></property>
		<!-- 认证成功以后跳转的页面 -->
		<property name="successUrl" value="/index.html"></property>
		<!-- 权限不足的时候,跳转的页面 -->
		<property name="unauthorizedUrl" value="/unauthorized.html"></property>
		<!-- 指定拦截规则 -->
		<property name="filterChainDefinitions">
			<!--
				authc : 框架提供的一个拦截器,必须认证通过,认证通过就可以访问,认证失败,无法访问
				anon : 框架提供的一个拦截器,可以匿名访问
				拦截器执行的时候是从上往下执行的,一旦有一个匹配成功执行了,后面的规则不再会被执行
				规则不可以折行 !!!!
			-->
			<value>
				/css/* = anon
				/data/* = anon
				/images/* = anon
				/js/** = anon
				/validatecode.jsp* = anon
				/** = authc
			</value>
		</property>
	</bean>
	<!-- 注册安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"></bean>

2 .用户登录安全校验,后台代码实现

2.1 UserController

 @RequestMapping(value = "loginShiro",method = RequestMethod.POST)
    public Map<String, Object> loginShiro(User user, HttpSession session) {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userStatus", 0);

        // 当前用户
        Subject subject = SecurityUtils.getSubject();

        // 对用户输入的密码进行加密
     	user.setPassword(PWDEncryptUtil.PWDEncrypt("MD5", user.getPassword()));
      System.out.println("传到userRealm的token带过去的password:"+user.getPassword());


        // 创建令牌token
        AuthenticationToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        System.out.println("传输过来的User:"+user.getUsername()+user.getPassword());

        try {
            // 执行登录
            // 参数就传递给Realm中doGetAuthenticationInfo方法的参数
            subject.login(token);
            // 该方法的返回值是由Realm中创建SimpleAuthenticationInfo对象时,传入的第一个参数决定的
            user = (User) subject.getPrincipal();
            System.out.println("保存到session中的User:"+user);
            // 把用户存入session
            session.setAttribute("name", user.getName());
            System.out.println("登陆的账户名称:"+user.getName());
            map.put("name",user.getName());
            map.put("userStatus", 1);
            return map;//登录成功

        } catch (UnknownAccountException e) {
            System.out.println("账户不存在");
            e.printStackTrace();
        } catch (IncorrectCredentialsException e) {
            System.out.println("密码错误");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("其他异常:" + e.getMessage());
        }
        return map;//跳转到登录页面
    }

2.2创建Realm

@Component
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;

    // 授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
       

	        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
	        // 需要根据当前的用户去查询对应的权限和角色
	        Subject subject = SecurityUtils.getSubject();
	        User user = (User) subject.getPrincipal();
	        
	        
	        if ("admin".equals(user.getUserName())) {//所有角色和所有权限都赋予给admin
	            // 内置管理员(超级管理员)的权限和角色是在数据库写死的
	            // 角色其实是权限的集合,并不是所有的权限都会包含在某一个角色中
	            List<Role> roles = roleMapper.findAll();
	            for (Role role : roles) {
	                info.addRole(role.getRemark());//role.getKeyword
	            }

	            List<Permission> permissions = permissionMapper.findAll();
	            for (Permission permission : permissions) {
	                info.addStringPermission(permission.getKeyword());
	            }
	        } else {//根据当前用户获取角色和权限
	            List<Role> roles = roleMapper.findbyUid(user.getId());
	            for (Role role : roles) {
	                info.addRole(role.getRemark());//role.getKeyword
	            }

	            List<Permission> permissions = permissionMapper.findbyUid(user.getId());
	            for (Permission permission : permissions) {
	                info.addStringPermission(permission.getKeyword());
	            }
	        }

	        return info;
    }

    // 认证方法
    // token就是Subject执行login方法传递进来的参数
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        // 根据用户名查找用户
        User user = userMapper.findByUsername(username);

        // 找到,比对密码
        if (user != null) {
            /**
             *
             * @param principal
             *            当事人,主体.往往传递从数据库中查询出来的用户对象
             * @param credentials
             *            凭证,密码(是从数据库中查询出来的密码)
             * @param realmName
             *
             */
            AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
            // 比对成功 处理后续逻辑
            // 比对失败 抛异常
            return info;
        }

        // 找不到 抛异常
        return null;
    }


}

2.3用户退出

    @RequestMapping(value = "/logout",method = RequestMethod.GET)
    public void logout(HttpServletRequest request, HttpServletResponse response,HttpSession session) throws IOException {
        Subject subject = SecurityUtils.getSubject();
        System.out.println(subject);
        if (subject != null) {
            try {
                //注销
                subject.logout();
                //清空session
                session.removeAttribute("name");
                session.removeAttribute("user");

            } catch (Exception ex) {
            }
        }
    }

3.配置applicationContext.xml

<!-- 注册安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- 注入realm -->
		<property name="realm" ref="userRealm"></property>
	</bean>

##三:动态授权方法

在applicationContext.xml中配置拦截规则

/hi.html = perms["courissser_pageQuery"]

在Realm中实现授权

// 授权方法
	// 该方法会在用户每次请求需要权限校验的资源时调用
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addStringPermission("courier_pageQuery");
		return info;
	}

##四:注解方式实现权限控制

在对应的方法上添加注解

	@RequiresPermissions("courier_delete")

配置applicationContext.xml

 <!--
		开启事务注解
		JDK代理方式 : 根据目标对象所实现的接口,创建了一个代理对象
		CGLib代理方式 : 创建一个目标对象的子类

		proxy-target-class:true,使用cglib代理
		proxy-target-class:false,使用jdk代理
	-->

<tx:annotation-driven proxy-target-class="true"
		transaction-manager="transactionManager" />

	<!-- 基于Spring自动代理的方式,为Service层的对象创建代理对象 -->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
		<!-- 开启cglib代理 -->
		<property name="proxyTargetClass" value="true"></property>
	</bean>

	<!--配置切面= 切点(向那里插入代码)+通知 (要插入的代码)-->
	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager"></property>
	</bean>

##五 标签方式实现权限控制

页面必须是jsp页面,jsp页面引入shiro

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

	<!-- 认证的用户可以看到被标签包裹的内容 -->
	<shiro:authenticated>
	当前用户已经通过认证了
</shiro:authenticated>
	<hr>
	<!-- 检查用户是否拥有对应的权限,如果有就可以看到内容,没有就看不到 -->
	<shiro:hasPermission name="courier_pageQuery">
	你拥有aa权限
</shiro:hasPermission>
	<hr>
	<!-- 检查用户是否拥有对应的角色,如果有就可以看到内容,没有就看不到 -->
	<shiro:hasRole name="admin">
你拥有admin权限
</shiro:hasRole>

</body>
</html>

##六 编码方式实现权限控制(不推荐)

subject.checkPermission("");// 检查权限
subject.checkRole("");// 检查角色

##七 Shiro权限控制方式总结

1.URL过滤器拦截实现权限控制
	底层基于shiro框架提供的过滤器,由过滤器拦截客户请求,实现权限校验.体现在spring框架的配置文件中.
	主要用于用户未登录时,保护系统资源
2.注解方式实现权限控制
	底层基于cglib代理,为Service类创建代理对象,由代理对象实现权限校验,体现在Service类方法上.
	主要用于用户登录后,保护系统资源
3.标签方式实现权限控制
	底层基于标签技术,动态展示页面中的元素,体现在jsp页面上.
	主要用于jsp页面,根据权限和角色保护对应的资源

 

版权声明:本文为niki_yeun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/niki_yeun/article/details/80856274