Shiro框架原理

Shiro框架

1.基本流程

1)依赖项

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-cas</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.2.2</version>
		</dependency>

2)加密包 org.apache.shiro.crypto

//盐
RandomNumberGenerator generator = new SecureRandomNumberGenerator();
String salt = generator.nextBytes().toHex();
//密码算法
String algorithmName = "md5";
//加密原码
Object source ="123456";
//盐
Object salt = generator.nextBytes().toHex();
//重复加密次数
int hashIterations =1;
SimpleHash simpleHash = new SimpleHash(algorithmName, source, salt, hashIterations);

3)XML配置

spring-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 ">
    <!-- 加密 -->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5"></property>
        <property name="hashIterations" value="1"></property>
    </bean>
    <!--  3end 业务-->
    <bean id="userRealm" class="com.uplooking.shiro.UserRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"></property>
    </bean>
    <!-- 2↑  权限管理 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"></property>
    </bean>
    <!-- 1.1↑ 权限拦截 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
    <!-- b end CAS认证过滤器 -->
    <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
        <property name="failureUrl" value="/user/login"/>
    </bean>
    <!-- 1.2↑ 过滤规则 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/user/login"/>
        <property name="successUrl" value="/user/login"/>
        <property name="filters">
            <map>
            	<!-- a↑ 过滤规则 -->
                <entry key="cas" value-ref="casFilter"/>
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /user/logout=logout
                /user/**=anon
                /static/**=anon
                /authority/**=authc
            </value>
        </property>
    </bean>
    <!--开启shiro的注解-->
    <bean id="advisorAutoProxyCreator"
          class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        <property name="proxyTargetClass" value="true"></property>
    </bean>
    <!-- Shiro生命周期处理器 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>

web.xml

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

4)注册(密码加密)

	正常业务流程 (Shiro框架加密工具)
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public Map<String, Object> saveUser(String path, UserVO record, MultipartFile file) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        UserVOExample example = new UserVOExample();
        //用户名唯一
        example.createCriteria().andUnameEqualTo(record.getUname());
        if(userMapper.countByExample(example)==0){
            example.clear();
            //联系电话唯一
            example.createCriteria().andUphoneEqualTo(record.getUphone());
            if(userMapper.countByExample(example)==0){
                //随机盐值
                String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
                record.setUsalt(salt);
                //密码加密
                String pwd = new SimpleHash(ShiroConsts.ALGORITHMNAME, UserConsts.DEFAULTPWD, salt,
                 						ShiroConsts.HASHITERATIONS).toHex();//md5,123456,随机盐值,1
                record.setUpwd(pwd);
                //默认积分
                record.setUfen(UserConsts.DEFAULTFEN);//0
                //默认状态
                record.setUstatus(UserConsts.DEFAULTUSATUS);//正常
                //后缀名
                //默认图片
                byte[] data = null;
                //为空使用系统(服务器上保存的)默认图片作为头像
                if(file==null || file.isEmpty()){
                	//获取图片的后缀,DEAFULTPHOTOPATH:系统默认图片的path
                    record.setUphoto(FileUtils.getSuffix(UserConsts.DEAFULTPHOTOPATH));
                    //复制一份系统默认图片
                    data = FileUtils.readFile(FileUtils.parentPath(path)+UserConsts.DEAFULTPHOTOPATH);
                }else{
                	//获取用户上传的图片后缀
                    record.setUphoto(FileUtils.getSuffix(file.getOriginalFilename()));
                    data = file.getBytes();
                }
                if(userMapper.insert(record)==1){
                    //图片上传
                    path = FileUtils.parentPath(path)+UserConsts.PHOTOUPLOADPATH+record.getUid()+record.getUphoto();
                    FileUtils.writeFile(path, data);
                    map.put(ConfigConsts.CODE, ConfigConsts.SUCCESSCODE);
                    map.put(ConfigConsts.MESSAGE, UserConsts.SAVEUSERSUSCCESSMESSGE);
                }else{
                    map.put(ConfigConsts.CODE, UserConsts.SAVEUSERFAILCODE);
                    map.put(ConfigConsts.MESSAGE, UserConsts.SAVEUSERFAILMESSAGE);
                }
            }else{
                map.put(ConfigConsts.CODE, UserConsts.USERPHONEEXISTCODE);
                map.put(ConfigConsts.MESSAGE, UserConsts.USERPHONEEXISTMESSAGE);
            }
        }else{
            map.put(ConfigConsts.CODE, UserConsts.USERNAMEEXISTCODE);
            map.put(ConfigConsts.MESSAGE, UserConsts.USERNAMEEXISTMESSAGE);
        }
        return map;
    }
}

登录

5)认证与授权

package com.uplooking.shiro;
//shiro
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private RoleMapper roleMapper;

    //授权(角色路由授权)
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取当前发起路由的对象信息
        Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
        System.out.println(primaryPrincipal);
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        if(primaryPrincipal instanceof UserVO){
            UserVO userVO=(UserVO) primaryPrincipal;
            List<String> roles = userVO.getRoles();
            //为当前用户进行角色授权
            info.addRoles(roles);
        }
        return info;
    }

    //认证(密码认证)
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) 
    throws AuthenticationException {
        //令牌 用户对象的载体->获取用户在认证时提交的用户名和(明文)密码
        String name=authenticationToken.getPrincipal().toString();
        //根据用户名获取用户对象,在进行认证
        UserVO userVO = userMapper.selectByUserName(name);
        if(userVO==null){
            throw new UnknownAccountException(ShiroConsts.UNKNOWACCOUNT);//用户名不存在
        }
        if(userVO.getUstatus()== UserConsts.LOCKUSATUS){//用户状态为103
            throw new LockedAccountException(ShiroConsts.ACCOUNTLOCK);//用户被冻结
        }
        //认证后存储登陆信息
        Object principal=userVO;
        //绑定当前用户的拥有角色
        List<String> unamelist=new ArrayList<>();
        List<String> unamezhlist=new ArrayList<>();

		//通过多表查询关联用户和角色
        UserRoleVOExample userRoleVOExample=new UserRoleVOExample();
        userRoleVOExample.createCriteria().andUruidEqualTo(userVO.getUid());
        List<UserRoleVO> userRoleVOS = userRoleMapper.selectByExample(userRoleVOExample);

        for (UserRoleVO userRoleVO : userRoleVOS) {
            RoleVO roleVO = roleMapper.selectByPrimaryKey(userRoleVO.getUrrid());
            unamelist.add(roleVO.getRname());
            unamezhlist.add(roleVO.getRnamezh());
        }
        userVO.setRoles(unamelist);
        userVO.setRoleZHs(unamezhlist);
        //获得加密后的密码
        Object hashed=userVO.getUpwd();
        //获得用户当前用户的盐值
        ByteSource salt=ByteSource.Util.bytes(userVO.getUsalt());
        //名称
        String realmName=this.getName();
        //认证
        return new SimpleAuthenticationInfo(principal,hashed,salt,realmName);
    }
}

控制层:

@RequestMapping(value="/user/login",method=RequestMethod.POST)
    public String method21(String name,String pwd,@RequestParam(name="rememberMe",defaultValue="false")Boolean rememberMe) throws Exception{

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(name, pwd,rememberMe);
        subject.login(token);//回调UserRealm类中的认证业务 认证出错抛异常
        return "redirect:/index.jsp";
    }

认证抛出异常处理类AdviceController.java

@ControllerAdvice
public class AdviceController {

    @ExceptionHandler(Exception.class)
    public String method(Exception ex){
        if (ex instanceof UnknownAccountException){
            return "redirect:/static/error/error-301.jsp";//用户不存在
        }
        if (ex instanceof LockedAccountException){
            return "redirect:/static/error/error-302.jsp";//用户名或密码错误
        }
        if (ex instanceof AuthorizationException){
            return "redirect:/static/error/error-303.jsp";//权限不足
        }
        return "redirect:/static/error/error-500.jsp";//错误
    }
}

配置解析

		//过滤规则
		/*
			authc	-> 认证后才能访问
			user	-> 记住我(Cookie)后可以访问
			anon	-> 匿名可以访问
			logout	-> 注销
			
		*/
		<property name="filterChainDefinitions">
			<value>
				/emp=user
				/user/logout=logout
				/user/**=anon
				/static/**=anon
			</value>
		</property>
		
	标签
		<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
		
		<shiro:authenticated>	-> 成功认证后
		<shiro:notAuthenticated> -> 未认证前
		<shiro:user>			-> 记住我之后 (用户对象序列化)
		<shiro:principal>		-> 当前认证用户信息(默认:用户名)

6)授权 (authorization) Controller

	1>标签 (治标不治本) ->盗链(路由)
	
	2>配置 (可读性弱)
		/dept/**=authc,roles[deptManager]
		/safe/list=authc,perms[sale:list]
		
	3>注解 (推荐)
		@RequiresRoles(value={"safeManager","admin"},logical=Logical.OR)//两种注释用其一
		@RequiresPermissions(value={"safe:list","safe:get"},logical=Logical.OR)//两种注释用其一
		@RequestMapping(value="/safe/list",method=RequestMethod.GET)
		public String method1() throws Exception{
			System.out.println("安全查询");
			return "safe/info";
		}

2.工作流程

1)登录时 回调认证业务
2)访问时 回调授权业务
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你不懂、、、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值