转:
流程:用户首先经过身份认证,通过后即可访问该资源
1.1 用户身份认证
??
1.2 授权流程
Shiro和Spring Security比较
(1)Shiro比Spring更容易使用,实现和理解
(2)Spring Security有更好的社区支持
(3)Apache Shiro在Spring Security处理密码学方面有一个额外的模块
(4)Spring-security 对spring 结合较好,如果项目用的springmvc ,使用起来很方便。但是如果项目中没有用到spring,那就不要考虑它了。
(5)Shiro 功能强大、且 简单、灵活。是Apache 下的项目比较可靠,且不跟任何的框架或者容器绑定,可以独立运行
1.1 Subject(当前操作用户)
?? 不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
1.2 SecurityManager(维护中心)
?? Shiro框架的核心,典型的Facade模式,用来协调内部组件实例,并提供安全管理的各种服务。
1.3 Realm(数据中心)
? 对用户认证(登录)和授权(访问控制)时,Shiro会从配置的Realm中查找用户及其权限信息。
?? 当配置Shiro时,至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
?? Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
(1)Authentication 认证 ---- 用户登录
(2)Authorization 授权 --- 用户具有哪些权限
(3)Cryptography 安全数据加密
(4)Session Management 会话管理
(5)Web Integration web系统集成
(6)Interations 集成其它应用,spring、缓存框架
(1)易于理解的 Java Security API;
(2)简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
(3)对角色的简单的签权(访问控制),支持细粒度的签权;
(4)支持一级缓存,以提升应用程序的性能;
(5)内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
(6)异构客户端会话访问;
(7)非常简单的加密 API;
(8)不跟任何的框架或者容器捆绑,可以独立运行
3.1 pom.xml中添加依赖
com.h2database
h2
runtime
org.apache.shiro
shiro-spring
1.3.2
3.2 编写测试Controller类
@RequiresPermissions("user:list")
@RequiresRoles("admin")
@ResponseBody
@RequestMapping("/hello")
public String hello(){
System.out.println(person);
return "hello world";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
@ResponseBody
public String defaultLogin() {
return "首页";
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
// 从SecurityUtils里边创建一个 subject Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 执行认证登陆
try {
subject.login(token);
} catch (UnknownAccountException uae) {
return "未知账户";
} catch (IncorrectCredentialsException ice) {
return "密码不正确";
} catch (LockedAccountException lae) {
return "账户已锁定";
} catch (ExcessiveAttemptsException eae) {
return "用户名或密码错误次数过多";
} catch (AuthenticationException ae) {
return "用户名或密码不正确!";
}
if (subject.isAuthenticated()) {
return "登录成功";
} else {
token.clear();
return "登录失败";
}
}
3.3 配置类
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录)可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
shiroFilterFactoryBean.setLoginUrl("/login");//登录页
shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
Map filterChainDefinitionMap = new LinkedHashMap<>();
//
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/front/**", "anon");
filterChainDefinitionMap.put("/api/**", "anon");
filterChainDefinitionMap.put("/admin/**", "authc");
filterChainDefinitionMap.put("/user/**", "authc");
filterChainDefinitionMap.put("/hello/**","perms[user:add]");
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
defaultSecurityManager.setRealm(customRealm());
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
defaultSecurityManager.setSubjectDAO(subjectDAO);
return defaultSecurityManager;
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
3.4 Realm
/**
* 权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = null;
String username = "";
if (Objects.nonNull(principalCollection)){
user = (User)principalCollection.getPrimaryPrincipal();
}
username = (String) SecurityUtils.getSubject().getPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//用户角色
Set roleSets = new HashSet<>();
roleSets.add("admin");
roleSets.add("test");
info.setRoles(roleSets);
//角色对应的权限
Set permissionSet = new HashSet<>();
permissionSet.add("user:show");
permissionSet.add("user:admin");
info.addStringPermissions(permissionSet);
return info;
}
/**
* 身份认证。即登录通过账号和密码验证登陆人的身份信息。
* @param authenticationToken
* @return
* @throws AuthenticationException
*/@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("-------身份认证方法--------");
//authenticationToken.getCredentials()----token?如何来?
String token = (String) authenticationToken.getCredentials();
if (StringUtils.isEmpty(token)){
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
Map parameterMap = request.getParameterMap();
Set> entrys = parameterMap.entrySet();
for (Map.Entry entry:entrys) {
System.out.println(entry.getKey()+"============"+entry.getValue());
}
throw new AuthenticationException("token为空");
}
User user = this.checkAuthenticationToken(token);
//String userName = (String) authenticationToken.getPrincipal();
//String userPwd = new String((char[]) authenticationToken.getCredentials()); return new SimpleAuthenticationInfo(user, token,getName());
}
转:
原文:https://www.cnblogs.com/wangtcc/p/14446920.html