springboot整合shiro-(1)快速入门

pom添加依赖

<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>

Shiro 配置

package config.compent;

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.company.project.interceptor.ShiroRealm;


/**  
 * @Description: Shiro的管理配置文件
 * @author:
 * @create:2019年2月25日 上午10:53:57 
 */
@Configuration
public class ShiroConfig {

    /**
     * @Description:将自己的验证方式加入容器
     * @return
     * @author:
     * @update:2019年2月25日 上午11:15:45
     */
    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        return shiroRealm;
    }

    /**
     * @Description:配置核心安全事务管理器
     * @return
     * @author:
     * @update:2019年2月25日 上午11:09:26
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        return securityManager;
    }

    /**
     * @Description:Filter工厂,设置对应的过滤条件和跳转条件
     * @param securityManager
     * @return
     * @author:
     * @update:2019年2月25日 上午11:09:15
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login_toLogin");
        //登录成功,跳转到首页
        shiroFilterFactoryBean.setSuccessUrl("/main/index");
        //错误页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/login_toLogin");
        Map<String,String> map = new HashMap<String, String>();
        //anon:url可以匿名访问
        //authc: 需要认证才能进行访问
        map.put("/static/**", "anon");
        map.put("/code.do", "anon");
        map.put("/login_login", "anon");
        map.put("/**", "authc");       
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }
 
    /**
     * @Description:开启shiro aop注解支持;Controller才能使用@RequiresPermissions等
     * @param securityManager
     * @return
     * @author:
     * @update:2019年2月25日 上午11:08:21
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

ShiroRealm.java

在认证、授权内部实现机制中都有提到,最终处理都将交给Real进行处理。因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO.

package com.company.project.interceptor;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
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 com.company.project.entity.system.user.User;
import com.company.project.service.system.login.LoginService;
import com.company.project.util.shiro.SessionSubject;

/**
 * @Description:shiro的认证和授权
 * @author:
 * @create:2019年2月27日 下午2:55:15
 */
public class ShiroRealm extends AuthorizingRealm {

	@Autowired
	private LoginService loginService;

	/**
	 * @Description:认证用户身份
	 * @param token
	 * @return
	 * @throws AuthenticationException
	 * @author:
	 * @update:2019年2月27日 下午2:56:53
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {
		//获取用户登录的用户ID、密码
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		String userId = token.getUsername();
		String password = String.valueOf(token.getPassword());
		User user = null;
		
		//根据用户名获取用户信息
		user = loginService.getUserByUsername(token.getUsername());
		if (user == null) {
			throw new UnknownAccountException("There is no user with username of " + userId);
		}
		if (!password.equals(user.getPassword().toLowerCase())) {
			throw new IncorrectCredentialsException("Password for username " + userId + " is incorrect!");
		}
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userId, password, getName());
		
		//将用户信息放到session中
		SessionSubject.setCurrentUser(user);
		
		return simpleAuthenticationInfo;
	}

	/**
	 * @Description:用户权限授权
	 * 授权的方法是在碰到<shiro:hasPermission name=''></shiro:hasPermission>标签的时候调用的
     * 它会去检测shiro框架中的权限(这里的permissions)是否包含有该标签的name值,如果有,里面的内容显示
     * 如果没有,里面的内容不予显示(这就完成了对于权限的认证.)
     *
     * shiro的权限授权是通过继承AuthorizingRealm抽象类,重载doGetAuthorizationInfo();
     * 当访问到页面的时候,链接配置了相应的权限或者shiro标签才会执行此方法否则不会执行
     * 所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可。
     *
     * 在这个方法中主要是使用类:SimpleAuthorizationInfo 进行角色的添加和权限的添加。
     * authorizationInfo.addRole(role.getRole()); authorizationInfo.addStringPermission(p.getPermission());
     *
     * 当然也可以添加set集合:roles是从数据库查询的当前用户的角色,stringPermissions是从数据库查询的当前用户对应的权限
     * authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(stringPermissions);
     *
     * 就是说如果在shiro配置文件中添加了filterChainDefinitionMap.put("/add", "perms[权限添加]");
     * 就说明访问/add这个链接必须要有“权限添加”这个权限才可以访问
     *
     * 如果在shiro配置文件中添加了filterChainDefinitionMap.put("/add", "roles[100002],perms[权限添加]");
     * 就说明访问/add这个链接必须要有 "权限添加" 这个权限和具有 "100002" 这个角色才可以访问
	 * @param pc
	 * @return
	 * @author:
	 * @update:2019年2月27日 下午4:31:50
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
		//获取用户
        User user = SessionSubject.getCurrentUser();

        //添加用户角色
        SimpleAuthorizationInfo authorizationInfo =  new SimpleAuthorizationInfo();
        String groupIds = user.getGroupId();
        System.out.println("groupIds:"+groupIds);
        if(groupIds != null){
        	String[] groupIdArr = groupIds.split(",");
        	for(String groupId: groupIdArr){
        		authorizationInfo.addRole(groupId);
        	}
        }
//        //获取用户权限
//        Set<Permission> permissions = this.permissionMapper.findPermissionsByRoleId(roles);
//        //添加权限
//        for (Permission permission:permissions) {
//            authorizationInfo.addStringPermission(permission.getPermission());
//        }

        return authorizationInfo;
	}

}

编写登录Controller

LoginController.java

	@RequestMapping(value = "/login_login", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public Object login(String userId, String password, String code, HttpServletRequest request) throws Exception {
		   String errInfo = "success";
		
			//使用shiro加入身份验证
			Subject subject = SecurityUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(userId, password);
			
			try {
				//登录操作
				subject.login(token);
			} catch (UnknownAccountException e) {
				errInfo = "usererror"; //用户名不存在
				logger.info("There is no user with username of {}",userId,e);
			} catch (IncorrectCredentialsException e) {
				errInfo = "usererror"; //用户名或密码有误
				logger.info("Password for username {} is incorrect",userId,e);
			} catch (AuthenticationException e) {
				errInfo = "usererror"; 
				logger.info("User of {} authentication failed",userId,e);
			}
		
		    //用户信息验证成功
			if("success".equals(errInfo)){
				//删除session中的验证码信息
				SessionSubject.removeSecurityCode();
				//记录用户登录信息日志
				loginService.insertLastLogin(request);
			}
			return ;
	}
	
	/**
	 * @Description:用户退出
	 * @return
	 * @author:
	 * @update:2019年3月18日 下午3:38:50
	 */
	@RequestMapping(value = "/logout")
	public ModelAndView logout() {
		Subject subject = SecurityUtils.getSubject();
		subject.logout();
		//页面跳转
	}

jsp页面

导入jstl标签库:
	<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

	<shiro:authenticated>用户[<shiro:principal/>]已身份验证通过 </shiro:authenticated> 
	<shiro:notAuthenticated>  未身份验证(包括记住我)</shiro:notAuthenticated> 
	<!-- 用户没有身份验证时显示相应信息,即游客访问信息 -->
    <shiro:guest>游客显示的信息</shiro:guest><br/>
    <!-- 用户已经身份验证/记住我登录后显示相应的信息 -->
    <shiro:user>用户已经登录过了</shiro:user><br/>
    <!-- 用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的 -->
    <shiro:authenticated>不是记住我登录</shiro:authenticated><br/>
    <!-- 显示用户身份信息,通常为登录帐号信息,默认调用Subject.getPrincipal()获取,即Primary Principal -->
    <shiro:principal></shiro:principal><br/>
    <!--用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证,与guest标签的区别是,该标签包含已记住用户 -->
    <shiro:notAuthenticated>已记住用户</shiro:notAuthenticated><br/>
    <!-- 相当于Subject.getPrincipals().oneByType(String.class) -->
    <shiro:principal type="java.lang.String"/><br/>
	<!-- 如果当前Subject有角色将显示body体内容 name="角色名" -->
    <shiro:hasRole name="admin">这是admin角色</shiro:hasRole><br/>
    <!-- 如果当前Subject有任意一个角色(或的关系)将显示body体内容。 name="角色名1,角色名2..." -->
    <shiro:hasAnyRoles name="admin,vip">用户拥有admin角色 或者 vip角色</shiro:hasAnyRoles><br/>
    <!-- 如果当前Subject没有角色将显示body体内容 -->
    <shiro:lacksRole name="admin">如果不是admin角色,显示内容</shiro:lacksRole><br/>
    <!-- 如果当前Subject有权限将显示body体内容 name="权限名" -->
    <shiro:hasPermission name="userInfo:add">用户拥有添加权限</shiro:hasPermission><br/>
    <!-- 如果当前Subject没有权限将显示body体内容 name="权限名" -->
	<shiro:lacksPermission name="userInfo:add">如果用户没有添加权限,显示的内容</shiro:lacksPermission><br/>

权限功能校验

经过上面的过程,已经可以对用户的身份进行校验,但是这个时候,但是权限控制好像没有什么作用,因为我们使用admin用户登录之后,在浏览器上访问地址 /userInfo/del发现也是可以使用的,其实我们还少了以下步骤,也就是开启注解支持后,在Controller的方法中添加对应权限

@RequiresPermissions("userInfo:del")
@RequestMapping(value = "/del",method = RequestMethod.GET)
@ResponseBody
public String del(Model model) {
    userService.del("wangsaichao");
    return "删除用户名为wangsaichao用户成功";
}

添加@RequiresPermissions(“userInfo:del”)然后重启项目,再次使用amdin登录之后,在浏览器上调用http://localhost:9090/userInfo/del就会跳转到以下错误页。证明权限校验成功。

原文参考:https://blog.csdn.net/qq_34021712/article/details/80294417

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值