Shiro与Sping Security均是java的安全框架,主要用于处理用户身份验证和授权。
验证与授权
常见场景为用户系统登录
shiro
Shiro易用性强,提供了认证,授权,加密,和会话管理功能。
Shiro的三大核心组件 :
Subject:即当前用户概念,不止代表着某用户,也可以是进程或任何可能的事物。
SecurityManager:即所有Subject的管理者,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。作用类似于SpringMVC中的DispatcherServlet,用于拦截所有请求并进行处理。
Realm:Realm是用户的信息认证器和用户的权限认证器,我们需要自己来实现Realm来自定义的管理我们自己系统内部的权限规则。SecurityManager要验证用户,需要从Realm中查询,它可以算是安全上的DAO,其封装了很多的类似数据库连接和数据源。
主要有以下几个功能点:
Authentication:身份认证(登录);
Authorzation:授权,判断用户是否由某个具体的权限;
Session Manager:会话管理;
Cryptography:加密,保护数据安全性,敏感数据密文存储;
WebSupport:web项目支持;
Caching:缓存,部分场景下提高数据存取效率;
Concurrency:多应用多线程的并发管理(权限共享);
RememberMe:配置后可以自动登陆。
配置文件
可以使用ini配置,但是在Spring项目中,这并不是最佳的配置方案。手动配置如下:
xml文件常规配置
1.配置web.xml文件
<!-- Shiro 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>
2.配置applicationContext.xml(略去部分内容)
<!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的ShiroDbRealm.java --> <bean id="myRealm" class="com.jadyer.realm.AuthRealm"/> <!-- 设置自定义的Realm应用 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm"/> <property name="cacheManager" ref="shiroCacheManager"/> <property name="rememberMeManager" ref="shiroRemembarMeManager"/> <property name="realm" ref="myRealm"/> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 安全管理器 --> <property name="securityManager" ref="securityManager" /> <!-- 一些操作的url --> <property name="loginUrl" value="/login" /> <property name="successUrl" value="/login/loginSuccessFull" /> <property name="unauthorizedUrl" value="/login/unauthorized" /> <!-- 自定义filter配置 --> <property name="filters"> <map> <entry key="authc"> <bean class="com.onefish.filter.CustomFormAuthenticationFilter"></bean> </entry> </map> </property> <!-- anon不需要认证 authc需要认证 user 验证通过或者rememberMe可以 --> <property name="filterChainDefinitions"> <value> /home* = anon / = anon /site/** = user /logout = logout /role/** = roles[admin,system] /vendor/** = perms[permssion:look] /** = authc </value> </property> </bean>
Spring boot项目中的配置
/**
* shiro的配置类
* @author Administrator
*
*/
@Configuration
public class ShiroConfiguration {
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(manager);
//配置登录的url和登录成功的url
bean.setLoginUrl("/login");
bean.setSuccessUrl("/");
//配置访问权限
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/tool", "anon"); //配置权限
filterChainDefinitionMap.put("/blogEditor", "anon");
filterChainDefinitionMap.put("/templates/*.*", "authc");
filterChainDefinitionMap.put("/logout", "logout"); //登出接口,自带过滤器已经实现基本的信息清除
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return bean;
}
//配置核心安全事务管理器
@Bean(name = "securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
System.err.println("--加载shiro--");
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(authRealm);
return manager;
}
//配置自定义的权限登录器
@Bean(name = "authRealm")
public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
AuthRealm authRealm = new AuthRealm();
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
//配置自定义的密码比较器
@Bean(name = "credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
return new CredentialsMatcher();
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor
authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}
}
重写Realm
重写Realm类,指定授权和认证的方式 下面是一个最简单的Realm
@Service
public class AuthRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//认证.登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;//获取用户输入的token
String username = utoken.getUsername();
User user = userService.findUserByName(username);
if(user!=null) {
return new SimpleAuthenticationInfo(user, user.getPswd(), this.getClass().getName());
//放入shiro.调用CredentialsMatcher检验密码
//注意这里 第一个对象是放入session用于后面校验用户的 在这选取了整个user对象
}else{
return null;
}
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
User user=(User) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
List<String> permissions=new ArrayList<>();
Set<Role> roles = user.getRoles();
if(roles.size()>0) {
for(Role role : roles) {
/*
Set<Module> modules = role.getModules();
if(modules.size()>0) {
for(Module module : modules) {
permissions.add(module.getMname());
}
}
*/
permissions.add(role.getName());
}
}
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermissions(permissions);//将权限放入shiro中.
return info;
}
}
重写、添加其余依赖
重写密码比较器
@Service
public class CredentialsMatcher extends SimpleCredentialsMatcher {
@Autowired
EncodeFacade encodeFacade;
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken utoken=(UsernamePasswordToken) token;
//获得用户输入的密码
String inPassword = new String(utoken.getPassword());
//获得数据库中的密码
String dbPassword=(String) info.getCredentials();
//进行密码的比对
encodeFacade.checkPsw(inPassword,dbPassword,utoken.getUsername());
return this.equals(inPassword, dbPassword);
}
编写登录接口
写登陆的认证,注意此处异常的处理
@RequestMapping(value="/login",method=Request.POST)
public String login(@RequestBody User user){
Subject subject=SecurityUtils.getSubject();
UsernamePasswordToken userToken=new UsernamePasswordToken(user.getName(),user.getPassword());
try{
subject.login(userToken);
return "登陆成功";
}catch (UnknownAccountException e){
return "用户名不存在";
}catch (IncorrectCredentialsException e){
return "密码错误";
}
}
注意各异常的分类和异常的捕获处理:
均是AuthenticationException的子类异常:
UnknownAccountException:错误的账号;
LockedAccountException:锁定的账号;
DisabledAccountException:禁用的账号;
IncorrctCredentialsException:错误的凭证;
ExpiredCredentialsException:过期的凭证;
ExcessiveAttemptsEXception:失败次数过多;
前端页面此处略
其他操作
一些常用操作: 获取当前subject(用户)标识,即前面new SimpleAuthenticationInfo中第一个参数
(User)SecurityUtils.getSubject().getPrincipal();
Spring Security
与Spring系列框架期和良好,功能较为强大。
maven引入
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>{spring-security-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>{spring-security-version}</version>
</dependency>
定义认证逻辑
配置Config类,继承WebSecurityConfigurerAdapter类,并重写该类原有部分方法
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override //
protected void configure(AuthenticationManagerBuilder auth){
super.configure(auth);
}
@Override
protected void configure(HttpSecurity http){
super.configure(http);
}
@Override
protected void configure(WebSecurity web){
super.configure(web);
}
}
重写
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 定义当需要用户登录时候,转到的登录页面
.and()
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.anyRequest() // 任何请求,登录后可以访问
.authenticated();
}
参考链接:权限控制框架-shiro


2019-09-29鱼鱼