——.用户验证核心模块简介
Subject :项目主体(关联SecurityManager)
SecurityManager :Shiro的的安全管理器(关联Realm)
Realm: Shiro访问数据库的桥梁
一。SpingBoot整合Shiro:
首先在Pom文件里导入Shiro的包。
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
第二步编写Shiro配置类
在配置之前我们先要编写一个自定义的Realm类。因为Realm是连接数据库的桥梁,Shiro会通过Realm来完成对用户权限和角色校验的逻辑。(这里暂时只编写用户授权逻辑)
package com.hukaihan.springbootshiro.shiro.config;
import com.hukaihan.springbootshiro.entity.User;
import com.hukaihan.springbootshiro.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//执行授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
//执行认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
User byName = userService.findByName(usernamePasswordToken.getUsername());
if(byName==null){
//返回null会抛出一个UnknownAccountException
return null;
}
//注意:不用自己判断只需返回一个AuthenticationInfo的子类,这里返回的是数据库中用户的密码
return new SimpleAuthenticationInfo("",byName.getPassword(),"");
}
}
上面的代码你可能不明白什么意思,但是不急,先往下看
由于Shiro框架的核心就是由过滤器Filter实现的,所以我要配置一个ShiroFilterFactoryBean(shiro内置的过滤器,实现用户权限角色拦截控制).
package com.hukaihan.springbootshiro.shiro.config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 设置
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultSecurityManager") DefaultWebSecurityManager defaultSecurityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(defaultSecurityManager);
Map<String,String> map = new LinkedHashMap<String,String>();
map.put("/delete","authc");
map.put("/update","authc");
/**
* Shiro常用过滤器
* 可以实现相关权限的拦截:
* anon:无需登陆认证
* authc:需要进行登陆认证才能访问的资源
* user:如果使用rememberMe的功能无需登录就可以直接访问
* perms:该资源必须得到相关权限才可以访问
* role:该资源必须得到角色资源才可以访问
*/
shiroFilter.setFilterChainDefinitionMap(map);
shiroFilter.setLoginUrl("/login");
return shiroFilter;
}
/**
* 创建defaultWebSecurityManager
* @return
*/
@Bean
public DefaultWebSecurityManager defaultSecurityManager(@Qualifier("myRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//关联Realm对象
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
}
/**
* 将UserRealm类加入spring
* @return
*/
@Bean
public UserRealm myRealm(){
return new UserRealm();
}
}
显然,这个过滤器依赖于一个SecurityManager,SecurityManager又依赖我们刚才写的Realm,一一配置好就可以了。
注意:
Shiro常用过滤器
* 可以实现相关权限的拦截:
* anon:无需登陆认证
* authc:需要进行登陆认证才能访问的资源
* user:如果使用rememberMe的功能无需登录就可以直接访问
* perms:该资源必须得到相关权限才可以访问
* role:该资源必须得到角色资源才可以访问
编写好过滤器以后,就会帮我们拦截我们配置的路径,根据上面的参数。拦截后默认会去ogin.jsp,所以我们在这里配置一下,把它配成我们需要的.login.html。
然后编写登陆方法:
@GetMapping("/dologin")
public String dologin(String uname,String pwd){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(uname,pwd);
try {
subject.login(usernamePasswordToken);
return "/index";
}catch (UnknownAccountException ex){
//登录失败,密码错误
System.out.println("用户名不存在");
return "/login";
}
catch (IncorrectCredentialsException ex){
//登录失败,密码错误
System.out.println("密码错误");
return "/login";
}
}
首先使用SecurityUtils帮我们生成一个Subject对象,也就是项目本体(我是这么理解的,不知道对不对哈哈,至少翻译的没错)。
将前台传来的用户名密码放在UsernamePasswordToken(用户令牌) 中,当然你还可以加验证码,不过要集成这个类加上验证码这个属性。
调用 subject.login(usernamePasswordToken);
之后他会去Realm类中执行我们编写的认证逻辑。
注意这个方法会抛出两个异常~:
UnknownAccountException:当用户名不存在时
IncorrectCredentialsException:密码错误时
这是你就可以回看我们之前写的Realm类了。当用户不存在时,返回一个null。这时Shiro就会帮我们抛出这个异常了。
成功就会返回到主页。至此简单的用户认证就做完了~