SpringBoot整合Shiro
引入pom依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
1.书写Shiro配置类
spring容器创建SecurityManager对象
@Bean
public DefaultWebSecurityManager securityManager(Realm realm){
//创建一个SecurityManager对象
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(realm);//自定义realm对象
return securityManager;
}
自定义自己书写的Realm
@Bean
public Realm realm(CredentialsMatcher credentialsMatcher){
MyRealm myRealm=new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher);//设置密码匹配器
return myRealm;
}
创建密码匹配器
@Bean
public CredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");//指定加密方式 MD5
credentialsMatcher.setHashIterations(1024);//加密的次数 1024次
return credentialsMatcher;
}
创建shiro的过滤器工厂,bean的名字是为了能和下面过滤器组件对应
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/toLogin"); //没有登录的用户请求需要登录的页面时自动跳转到登录页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); //没有权限默认跳转的页面,登录的用户访问了没有被授权的资源自动跳转到的页面
Map<String,String> map=new HashMap<>();
map.put("/login","anon"); //配置不登录不会被拦截的链接
map.put("/**","authc"); //配置不登录会被拦截的链接
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
注入过滤器组件
public FilterRegistrationBean<Filter> filter(){
FilterRegistrationBean registrationBean=new FilterRegistrationBean();
registrationBean.setName("shiroFilter");//这个名字要和上面shiro过滤器工厂的bean名字对应
registrationBean.addUrlPatterns("/*");
registrationBean.setFilter(new DelegatingFilterProxy());
return registrationBean;
}
2.书写自定义的Realm
自己书写的Realm要继承AuthorizingRealm类
重写doGetAuthenticationInfo方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.获取账号
String username = authenticationToken.getPrincipal().toString();
//2.根据账号查询用户信息
QueryWrapper<Login> wrapper = new QueryWrapper<>(); //条件信息 根据用户名是否相等作为条件
wrapper.eq("username",username);
Login login = loginMapper.selectOne(wrapper);
if (login!=null){ //如果为空说明用户名错误
ByteSource byteSource=ByteSource.Util.bytes(login.getSalt());
//密码的比对有shiro自动比对------->shiro会把用户输入的密码按照密码匹配器进行加密 并按照自己指定的盐
/**
* 参数
* 1 账号
* 2 数据库密码
* 3 数据库盐
*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,login.getPassword(),byteSource,this.getName());
return info;
}
return null;
}
简单测试,就只写controller层
@PostMapping("login")
public Result login(String username, String password){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);//自动调用Realm的认证器
return new Result(200,"登录成功",null);
}catch (Exception e){
return new Result(500,"登录失败",null);
}
}
因为是加密过的密码,所以数据库的密码也要加密存储
浏览器测试
输入错误的密码
输入错误的用户名
输入正确的用户名密码