Springboot集成Shiro实现认证

Apache Shiro是什么?

Apache Shiro是一个强大且易用的Java安全框架,能够执行身份验证、授权、加密和会话管理等。

Apache Shiro的主要API

Subject

Subject为“当前操作用户”。但是,在Shiro中,Subject这一概念可以理解为"账户",但并不局限于"帐户",而是与shrio交互的当前应用。

SecurityManager

SecurityManager(安全管理器)是Shiro框架的核心,Shiro通过SecurityManager实现安全管理的功能和服务。

Realm

  • Realm是安全数据源,其中包含认证和授权数据。

    认证可以理解为登录,认证数据为正确的账户及口令信息,当对用户执行认证(登录)时,shiro会与Realm中的认证数据比较进行登录验证。

    授权数据可以理解为用户拥有的权限,当用户进行某一操作时,Shiro会与Realm中的授权数据比对,验证用户是否拥有此操作的权限(授权验证)。

  • 当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。

    Shiro内置了很多可用的安全数据源(又名目录)的Realm, 如果内置的Realm不能满足需求,可以自定义Realm实现。

Apache Shiro与Springboot集成

依赖引入

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.4.1</version>
</dependency>

开发集成shiro的配置类

开发一个集成shiro的spring配置类

@Configuration
public class ShiroConfigure {
	private static final Logger LOG = LoggerFactory.getLogger(ShiroConfigure.class);    
	
	//注册跨域过滤器
	//开发和配置安全数据源	
	//配置shiro过滤器拦截规则定义
	
	
}

注册跨域过滤器

shiro过滤器会优先于springboot拦截请求,springboot的跨域设置将不起作用,因此需要专门注册跨域过滤器并设置其为过滤器链中的第一个。

 	@Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        
    	final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        
    	final CorsConfiguration config = new CorsConfiguration();
    	
        // 允许cookies跨域
        config.setAllowCredentials(true);
        
        // 允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedOrigin("*");
        
        // 允许访问的头信息,*表示全部
        config.addAllowedHeader("*");
        
        // 预检请求(options请求)的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.setMaxAge(1L);
        
        // 允许提交请求的方法,*表示全部允许
        config.addAllowedMethod("*");
        /*
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        */
        
        //设置允许跨域的路径
        source.registerCorsConfiguration("/**", config);

        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
        
        // 设过滤器的优先级
        bean.setOrder(0);

        return bean;
    }

开发和配置安全数据源

	/*
	 * 配置安全数据源Realm 此处必须要命名“authorizer”,
	 * 因为shiro会自动寻找名称为“authorizer”的、并实现接口Authorizer的对象,
	 * 而AuthorizingRealm正是接口Authorizer的实现类
	 */
	@Bean("authorizer")
	@Autowired
	public AuthorizingRealm saftyRealm(ShiroService shiroService) {

		return new AuthorizingRealm() {

			/**
			 * 获取认证信息(即包含当前用户帐户和合法密码等信息) shiro在登录认证时需要通过该方法获取认证信息。 参数 AuthenticationToken
			 * 认证令牌(如:一组用户名和密码就是一个认证令牌)
			 */
			@Override
			protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {

				String userId = (String) token.getPrincipal();// 获得当事人(当前用户账号)

				User user = shiroService.getUser(userId);

				/*
				 * 如果不存在前用户信息,返回null
				 */
				if (user == null) {
					return null;
				}

				/*
				 * 创建当前用户
				 */
				CurrUser currUser = new CurrUser(user.getU_id(), user.getU_name());

				/*
				 * 创建认证信息,三个构造参数含义依次如下: 参数1:principal当前用户 参数2:credentials认证凭证(如:口令、密码等)
				 * 参数3:realm名称
				 */
				SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currUser, user.getU_pwd(), this.getName());

				/*
				 * 返回认证信息
				 */
				return info;
			}

			/**
			 * 获取当事人(当前用户)授权信息,shiro在检查访问是否经过授权时需要通过该方法获取授权信息。(本例不考虑授权验证,因此返回null)
			 * 参数PrincipalCollection 当事人集合
			 */
			@Override
			protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
				// TODO Auto-generated method stub
				return null;
			}

		};
	}

配置shiro过滤器拦截规则定义

	@Bean
	@Autowired
	public ShiroFilterChainDefinition shiroFilterChainDefinition(ShiroService shiroService) {

		DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

		/*
		 * 可匿名访问资源
		 */
		chainDefinition.addPathDefinition("/safty/login/**", "anon");

		// 其它资源必须经过认证
		chainDefinition.addPathDefinition("/**", "authc");

		LOG.debug("=====Shiro安全规则=======================================================================");
		LOG.debug(chainDefinition.getFilterChainMap().toString());
		LOG.debug("=====Shiro安全规则=======================================================================");

		return chainDefinition;
	}

在配置文件application.yaml中配置shiro

shiro:
  loginUrl: /safty/login/loginTo #拦截需要认证而未认证的请求后的跳转路径

登录示例

@RestController
@RequestMapping("/safty/login")
public class LoginController {

	@PostMapping("/user")
	public Result login(@RequestBody UserDto userDto) {

		try {
			Subject subject = SecurityUtils.getSubject();

			// 创建登录令牌
			UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userDto.getU_id(),
					userDto.getU_pwd());

			// 登录,该方法声明抛出异常,可以捕获异常,并进行应对处理
			subject.login(usernamePasswordToken);

			// 是否通过认证
			if (subject.isAuthenticated()) {

				// 获得当前用户信息
				CurrUser currUser = (CurrUser) subject.getPrincipal();

				// 将当前用户放入Session。注:这里的Session是由Shiro提供的。
				subject.getSession().setAttribute(Constants.SESSION_ATTR_CURR_USER, currUser);

				return Result.success("登录成功!");
			}

			return Result.fail("登录失败!");

		} catch (UnknownAccountException e) {
			return Result.fail("用户名不存在!");
		} catch (IncorrectCredentialsException e) {
			return Result.fail("账户密码不正确!");
		} catch (LockedAccountException e) {
			return Result.fail("用户名被锁定 !");
		} catch (Exception e) {
			e.printStackTrace();
			return Result.fail("系统错误!");
		}
	}

	@GetMapping("/loginTo")
	public Result loginTo() {
		return Result.unLogged();
	}

}

退出示例

@RestController
@RequestMapping("/safty/home")
public class HomeController {
	
	//......
	
	//退出系统
	@DeleteMapping("/user")
	public Result logout() {
		
		SecurityUtils.getSubject().getSession().removeAttribute(Constants.SESSION_ATTR_CURR_USER);
		//注销
		SecurityUtils.getSubject().logout();		
		
		return Result.success("您已成功退出系统!");
	}

}

其它相关类和配置文件

ShiroService

public interface ShiroService {

	/**
	 * 获取用户信息
	 * @param userId
	 * @return
	 */
	User getUser(String userId);	

}

ShiroDao

public interface ShiroDao {	

	/**
	 * 根据用户帐号查询用户信息
	 * @param userId
	 * @return
	 */
	@Select("select u_id,u_name,u_pwd from sys_user where u_id=#{userId}")
	User findUser(String userId);

	
}

启动类

@SpringBootApplication
@MapperScan({ "org.sunshine.dye.dao", "org.sunshine.dye.shiro.dao" })
public class SunshineDyeApp {

	public static void main(String[] args) {

		SpringApplication.run(SunshineDyeApp.class, args);

	}

}

修改日志配置

logging:
  level:
    web: trace
    org.sunshine.dye.dao: debug
    org.sunshine.dye.shiro.dao: debug

测试

上述配置和相关代码开发完成后,即可进行测试调试。

附:案例源码

案例源码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值