Shiro学习笔记

Shiro核心对象

  1. Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。
    Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

  2. SecurityManager
    SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。

  3. Authenticator
    Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

  4. Authorizer Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

  5. realm
    Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
    注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。

  6. sessionManager
    sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。

Shiro依赖

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

Shiro配置

@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		//Shiro的核心安全接口,这个属性是必须的
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		//当拦截到请求时,去AjaxPermissionsAuthorizationFilter()处理
		//去AjaxPermissionsAuthorizationFilter是自定义的类,继承与FormAuthenticationFilter
		Map<String, Filter> filterMap = new LinkedHashMap<>();
		filterMap.put("authc", new AjaxPermissionsAuthorizationFilter());
		shiroFilterFactoryBean.setFilters(filterMap);
		/*定义shiro过滤链  Map结构
		 * Map中key(xml中是指value值)的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的
		 * anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种
		 * authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
		 */
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
         /* 过滤链定义,从上向下顺序执行,一般将 / ** 放在最为下边:这是一个坑呢,一不小心代码就不好使了;
          authc:所有url都必须认证通过才可以访问; anon:所有url都可以匿名访问 */
		filterChainDefinitionMap.put("/", "anon");
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/login/auth", "anon");
		filterChainDefinitionMap.put("/login/getCode", "anon");
		filterChainDefinitionMap.put("/login/logout", "anon");
		filterChainDefinitionMap.put("/error", "anon");
		filterChainDefinitionMap.put("/swagger-ui.html", "anon");
		filterChainDefinitionMap.put("/doc.html", "anon");
		filterChainDefinitionMap.put("/swagger-resources/**", "anon");
		filterChainDefinitionMap.put("/v2/**", "anon");
		filterChainDefinitionMap.put("/webjars/**", "anon");
		filterChainDefinitionMap.put("/**", "authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}
	//配置securityManager
    @Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		//这里要设置Realm
		securityManager.setRealm(userRealm());
		return securityManager;
	}
	//配置userRealm,如果要使用登录加密则配置setCredentialsMatcher
	@Bean
	public UserRealm userRealm() {
		UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
		return userRealm;
	}
	//配置加密规则
	@Bean()
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		//散列算法:这里使用MD5算法;
		hashedCredentialsMatcher.setHashAlgorithmName("md5");
		//散列的次数,比如散列两次,相当于 md5(md5(""));
		hashedCredentialsMatcher.setHashIterations(2);
		//storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
		hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
		return hashedCredentialsMatcher;
	}

自定义的realm

public class UserRealm extends AuthorizingRealm {
	private Logger logger = LoggerFactory.getLogger(UserRealm.class);

	//登录的service,就是dao接口,作用获取数据库用户信息
	@Autowired
	private LoginService loginService;
	@Autowired
	private UserService userService;

	@Override
	@SuppressWarnings("unchecked")
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		//获取用户
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		String primaryPrincipal = (String)principals.getPrimaryPrincipal();
		System.out.println("调用权限验证:" + primaryPrincipal);
		//获取用户信息
		JSONObject user = loginService.getUser(primaryPrincipal);
		String role = (String) user.get("role_name");
		//为用户添加角色
		authorizationInfo.addRole(role);
		//返回authorizationInfo
		return authorizationInfo;
	}

	/**
	 * 验证当前登录的Subject
	 * LoginController.login()方法中执行Subject.login()时 执行此方法
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		String loginName = (String) authcToken.getPrincipal();
		// 获取用户密码
		String password = new String((char[]) authcToken.getCredentials());
		JSONObject user = loginService.getUser(loginName);
		if (user == null) {
			//没找到帐号
			throw new UnknownAccountException();
		}

		user.put("roleName",loginService.getUser(loginName).get("role_name"));
		//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
				user.getString("login_name"),
				user.getString("password"),
				ByteSource.Util.bytes(user.getString("salt")),
				getName()
		);
		//session中不需要保存密码
		user.remove("password");
SecurityUtils.getSubject().getSession().setAttribute(Constants.SESSION_USER_INFO, user);
		return authenticationInfo;
	}
}

编写Controller的登录逻辑

public JSONObject authLogin(JSONObject jsonObject) {
		String username = jsonObject.getString("loginName");
		String password = jsonObject.getString("password");
		String code = jsonObject.getString("code");
		JSONObject data = new JSONObject();
		Subject currentUser = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(username, password);

		//判断验证码
		if(code == null || code.equals("")){
			return CommonUtil.failJson(data);
		}
		String relcode = (String)currentUser.getSession().getAttribute("code");

		if(relcode == null || relcode.equals("")){
			data.put("code", "201");
			data.put("msg", "验证码失效");
			return data;
		}
		if(!relcode.equals(relcode)){
			data.put("code", "201");
			data.put("msg", "验证码错误");
			return data;
		}
		try {
		    //交给shiro验证,实质是调用UserRealm里逻辑,失败则会抛出异常。
			currentUser.login(token);
			data.put("code", "200");
			data.put("msg", "请求成功");

		} catch (AuthenticationException e) {
			data.put("code", "201");
			data.put("msg", "账号或密码错误");
		}
		return data;
	}

注册加密逻辑

如果采用加密形式,则注册时候要将密码加密存到数据库

 		String originalPassword = user.getPassword(); //原始密码
        String hashAlgorithmName = "md5"; //加密方式
        int hashIterations = 2; //加密的次数
        //随机盐
        String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
        //加密
        SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, originalPassword, salt, hashIterations);
        //加密后密码
        String encryptionPassword = simpleHash.toString();
		//存到用户对象里
        user.setSalt(salt);
        user.setPassword(encryptionPassword);
        //...其他逻辑
        //存到数据库
        userDao.addUser(user);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值