Shiro-与Spring整合

添加如下jar包:

<!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>${shiro.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

web.xml添加Spring对Filter的代理,

<filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

shiro在spring中的配置信息:

<!--Shiro拦截器-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager"/>
		<property name="loginUrl" value="login.html"/>
		<!--设置无权限的地址-->
		<property name="unauthorizedUrl" value="view/403.html"/>
		<property name="filterChainDefinitions">
			<!--从上往下匹配,匹配到即返回-->
			<value>
				<!--不需要校验-->
				/view/login.html = anon
				/testLogin = anon
			</value>
		</property>
	</bean>

	<!--创建SecurityManager-->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customerRealm"/>
	</bean>
	<bean id="customerRealm" class="com.test.shiro.realm.CustomerRealm">
		<property name="credentialsMatcher" ref="credentialsMatcher"/>
	</bean>
	<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<property name="hashAlgorithmName" value="md5"/>
		<!--一次加密-->
		<property name="hashIterations" value="1"/>
	</bean>

定义了密码加密的方式和加密次数

自定义的realm

public class CustomerRealm extends AuthorizingRealm {

    private static Logger logger = LoggerFactory.getLogger(UserController.class);

    Map<String, String> userNameAndPassword = new HashMap<>();
    {
        //1通过MD5加盐加密后
        userNameAndPassword.put("user1", "55f312f84e7785aa1efa552acbf251db");
        userNameAndPassword.put("user2", "55f312f84e7785aa1efa552acbf251db");
        super.setName("customerRealm");
    }

    Map<String, String> userNameAndRole = new HashMap<>();
    {
        userNameAndRole.put("user1", "admin");
        userNameAndRole.put("user2", "user");
    }

    Map<String, Set<String>> roleAndPermission = new HashMap<>();
    {
        Set<String> lstAdminPermission=new HashSet<>();
        lstAdminPermission.add("delete");
        lstAdminPermission.add("select");
        roleAndPermission.put("admin",lstAdminPermission);

        Set<String> lstUserPermission=new HashSet<>();
        lstUserPermission.add("select");
        roleAndPermission.put("user",lstUserPermission);
    }

    /**
     * 授权
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName = (String) principals.getPrimaryPrincipal();
        logger.info("进行授权认证,传递的用户名:{}", userName);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        logger.info("从数据库中获取权限数据,用户名为{}",userName);
        //模拟数据库通过用户名获取角色数据
        Set<String> roles = new HashSet<>();
        roles.add(userNameAndRole.get(userName));
        simpleAuthorizationInfo.setRoles(roles);

        //模拟通过角色获取权限数据
        Set<String> permissions =roleAndPermission.get(userNameAndRole.get(userName));
        simpleAuthorizationInfo.setStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }

    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("Shiro授权校验-doGetAuthenticationInfo");
        //从主体传过来的认证信息中,获取用户名
        String userName = (String) authenticationToken.getPrincipal();
        logger.info("登陆的用户名{}", userName);
        //模拟通过用户名到数据库中获取凭证
        String password = userNameAndPassword.get(userName);
        if (password == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, password, "customerRealm");
        //----------------设置盐----------
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(SALT));
        return authenticationInfo;
    }

    private static final String SALT="salt";

    public static void main(String[] args) {
        Md5Hash md5Hash = new Md5Hash("1",SALT);
        System.out.println(md5Hash.toHex());
    }
}

加载md5加密后的密码到内存中,模拟从数据库中读取。定义各个角色及权限,重写认证和授权方法。
登陆接口:

/**
     * 登陆--测试Shiro认证
     * @param user
     * @return
     */
    @RequestMapping(value = "/testLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
    @ResponseBody
    public Object testLogin(User user, HttpServletRequest request, HttpServletResponse response){
        logger.info("-----------登陆校验------------------");
        Subject subject= SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(user.getUsername(),user.getPassword());

        //密码校验
        try{
            token.setRememberMe(true);
            subject.login(token);
            logger.info("是否已认证:"+subject.isAuthenticated());
        }catch (Exception e){
            logger.error("校验异常{}",e);
            return "登陆失败";
        }
        return "登陆成功";
    }
  1. 权限控制-通过配置文件的方式
    在filterChainDefinitions中添加如下信息
<property name="filterChainDefinitions">
			<!--从上往下匹配,匹配到即返回-->
			<value>
				<!--不需要校验-->
				/view/login.html = anon
				/testLogin = anon
				<!--权限校验-->
				<!--测试自定义filter及角色满足一个即可-->
				/testPropertiesRoles1 = roles["admin"]
				/testPropertiesRoles2 = roles["user"]
				/testPerpertiesPerms1 = perms["delete"]
				/testPerpertiesPerms2 = perms["select"]
				/* = authc
			</value>
		</property>

定义了/testPropertiesRoles1接口只有admin才能访问,/testPropertiesRoles2只能说user才能访问。testPerpertiesPerms1必须要有delete权限才能访问,testPerpertiesPerms2必须要有select权限才能访问,/testLogin接口不需要鉴权。如果没有权限,会跳转到自定义的403页面。
问题:在角色中,如果配置成如下的形式

/testPropertiesRoles2 = roles["admin","user"]

则只有用户同时具有admin和user的角色才能访问,即判断中为并,需要之定义filter

<!--Shiro拦截器-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager"/>
		<property name="loginUrl" value="login.html"/>
		<!--设置无权限的地址-->
		<property name="unauthorizedUrl" value="view/403.html"/>
		<property name="filterChainDefinitions">
			<!--从上往下匹配,匹配到即返回-->
			<value>
				<!--不需要校验-->
				/view/login.html = anon
				/testLogin = anon
				<!--权限校验-->
				<!--测试自定义filter及角色满足一个即可-->
				/testPropertiesRoles1 = roles["admin"]
				/testPropertiesRoles2 = roles["user"]
				/testPerpertiesPerms1 = perms["delete"]
				/testPerpertiesPerms2 = perms["select"]
				<!--自定义Filter权限控制-->
				<!--/testPropertiesRoles2 = rolesOr["admin","user"]-->
				/* = authc
			</value>
		</property>
		<property name="filters">
			<util:map>
				<entry key="rolesOr" value-ref="rolesOrFilter"/>
			</util:map>
		</property>
	</bean>
	<!--自定义Filter-解决role中一个用户角色需要满足配置的所有的角色-->
	<bean id="rolesOrFilter" class="com.test.shiro.realm.RolesOrFilter"/>

自定义rolesOrFilter。

public class RolesOrFilter extends AuthorizationFilter {

    private static Logger logger = LoggerFactory.getLogger(RolesOrFilter.class);

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {
        Subject subject=getSubject(request,response);
        String[] roles=(String[]) o;
        if(roles==null||roles.length==0){
            logger.info("不需要授权");
            return true;
        }
        for (String role:roles){
            if(subject.hasRole(role)){
                return true;
            }
        }
        return false;
    }
}

四个用于测试权限的接口:

/**
     * 只能admin访问
     * @return
     */
    @RequestMapping(value = "/testPropertiesRoles1",method = RequestMethod.GET)
    @ResponseBody
    public String testPropertiesRole1(){
        logger.info("---------userName----------:{}",SecurityUtils.getSubject().getPrincipal());
        return "testPropertiesRoles1";
    }

    /**
     * 只有user可以访问,(配置为如果在shiro配置文件中配置成roles["admin","user"],需要当前用户的角色
     * 都满足才能访问)
     * @return
     */
    @RequestMapping(value = "/testPropertiesRoles2",method = RequestMethod.GET)
    @ResponseBody
    public String testPropertiesRoles2(HttpServletRequest request){
        logger.info("---------userName----------:{}",SecurityUtils.getSubject().getPrincipal());
        for (Cookie cookie:request.getCookies()){
            logger.info("cookieKey:{},cookieValue:{},maxAge:{}",cookie.getName(),cookie.getValue(),cookie.getMaxAge());
        }
        return "testPropertiesRoles2";
    }

    /**
     * 测试-必须要有delete的权限才能访问
     * @return
     */
    @RequestMapping(value = "/testPerpertiesPerms1",method = RequestMethod.GET)
    @ResponseBody
    public Object testPerpertiesPerms1(){
        logger.info("---------userName----------:{}",SecurityUtils.getSubject().getPrincipal());
        return "testPerpertiesPerms1";
    }

    /**
     * 测试-必须要有select的权限才能访问
     * @return
     */
    @RequestMapping(value = "/testPerpertiesPerms2",method = RequestMethod.GET)
    @ResponseBody
    public Object testPerpertiesPerms2(){
        logger.info("---------userName----------:{}",SecurityUtils.getSubject().getPrincipal());
        return "testPerpertiesPerms2";
    }
  1. 权限控制-通过注解的方式
//-------------------------注解方式----------------------------
    /**
     * 测试RequiresRoles注解,必须要admin才能访问
     * @return
     */
    @RequiresRoles("admin")
    @RequestMapping(value = "/testRequireRoles1",method = RequestMethod.GET)
    @ResponseBody
    public String testRequireRoles1(){
        return "testRequireRoles1";
    }

    /**
     * 测试RequiresRoles注解,必须是user才能访问
     * @return
     */
    @RequiresRoles("user")
    @RequestMapping(value = "/testRequireRoles2",method = RequestMethod.GET)
    @ResponseBody
    public String testRequireRoles2(){
        return "testRequireRoles2";
    }

已上@RequiresRoles注解说明的一个接口只有admin才能访问,第二个接口只有user才能访问,
没有权限时将会报异常信息

 Request processing failed; nested exception is org.apache.shiro.authz.UnauthorizedException: Subject does not have role [user]

在这里插入图片描述
参考某课网。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值