1、简介
shiro是由apache基金会旗下的强大的安全校验框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,从最小的移动应用程序到最大的网络和企业应用程序。本博客展示一个用户认证的demo,看看用shiro怎么来做用户认证的。
2、maven依赖
这里的sprigboot的版本是2.1.6.RELEASE
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
3、sql
用户信息表
CREATE TABLE `userinfo` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`user_name` varchar(64) DEFAULT NULL,
`name` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL,
`salt` varchar(32) DEFAULT NULL,
`status` smallint(2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4、springboot 配置shiro
shiroConfig.java
package com.example.demo2.config;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
/**
* @author yy
* @version 1.0.0
* <ul>
* <li>project : demo2</li>
* <li>package : com.example.demo2.config</li>
* </ul>
* @since 2019/7/23 15:59
**/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//拦截器.
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterChainDefinitionMap.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列的次数,比如散列两次,相当于 md5(md5(""));
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");
mappings.setProperty("UnauthorizedException","403");
r.setExceptionMappings(mappings);
r.setDefaultErrorView("error");
r.setExceptionAttribute("ex");
return r;
}
}
MyshiroRealm.java
package com.example.demo2.config;
import com.stock.stockapi.dto.UserInfoDTO;
import com.stock.stockapi.dto.UserRoleDTO;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
/**
* @author K0171005
* @version 1.0.0
* <ul>
* <li>project : demo2</li>
* <li>package : com.example.demo2.config</li>
* </ul>
* @since 2019/7/23 16:03
**/
@Slf4j
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
RestTemplate restTemplate;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
UserInfoDTO userInfoDTO = (UserInfoDTO)principalCollection.getPrimaryPrincipal();
HttpEntity<UserInfoDTO> entity = new HttpEntity<>(userInfoDTO);
ResponseEntity<Boolean> responseEntity = restTemplate.
getForEntity("http://localhost:8080/stock/save", Boolean.class, "");
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String userName = (String) token.getPrincipal();
log.info("当前用户token {}", token.getCredentials());
QueryUserInfoReqDTO reqDTO = new QueryUserInfoReqDTO();
reqDTO.setUserName(userName);
UserInfoDTO userInfoDTO = restTemplate.postForObject("http://localhost:8080/user/queryUserByName", reqDTO, UserInfoDTO.class);
if (userInfoDTO != null) {
SimpleAuthenticationInfo authorizationInfo =
new SimpleAuthenticationInfo(userInfoDTO, userInfoDTO.getPassword(), getName());
return authorizationInfo;
}
return null;
}
}
我这里直接用来restful来提供远程服务,大家也可以在项目中使用其他的远程过程调用,(例如dubbo,不过需要搭建注册中心,本人闲麻烦)
下面来介绍一些几个主要bean的作用。
ShiroFilterFactoryBean 的作用主要是用来拦截需要验证的url。可以看到上面配置了登录拦截,以及权限验证拦截,和验证通过之后跳转的页面。
MyShiroRealm
这个是自定义的Realm,继承了shiro的AuthorizingRealm,其中有两个重要的方法,一个是doGetAuthorizationInfo(权限校验),一个是doGetAuthenticationInfo(认证校验),在ShiroFilterFactoryBean 中配置的拦截url,都会经过这两个方法的校验。也是shiro的核心方法。
结语:
以上就是本人最近学习shiro的例子,希望能给大家带来帮助。