1.shiro4中pom.xml中进行相应的配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<!-- 1-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.18</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.18</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.配置数据库连接
spring:
datasource:
druid:
url: jdbc:mysql://127.0.0.1/db_shior2
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
initial-size: 1
min-idle: 1
max-active: 20
mybatis:
mapper-locations: classpath:mappers/*Mapper.xml
type-aliases-package: com.li.beans
server:
port: 8066
3.首先创建UserMapper.xml、其次创建UserDao接口
<?xml version="1.0" encoding="UTF-8" ?><!--3.mapper接口中没有方法 ,则xml配置文件无需添加-->
<resultMap id="userMap" type="User">
<id column="user_id" property="userId"></id>
<result column="username" property="userName"></result>
<result column="password" property="userPwd"></result>
<result column="password_salt" property="pwdSalt"></result>
</resultMap>
<select id="queryUserByUserName" resultMap="userMap">
select * from tb_users
where username = #{username}
</select>
4.创建UserDaoTest对象
import com.li.LiApplication;
import com.li.beans.User;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import static org.junit.Assert.;
/
-
@SpringBootTest(classes= LiApplication.class)
-
启动类扫描@MapperScan(basePackages = “com.li.dao”)
-
才能注入userDao
-
@RunWith(SpringRunner.class)加junit4进行测试
-
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes= LiApplication.class)
public class UserDaoTest {@Resource
private UserDao userDao;
//使用junit4进行测试
@org.junit.Test
public void queryUserByUserName() throws Exception {
User user = userDao.queryUserByUserName(“zhangsan”);
System.out.println(user);
}
}
5.主启动类中进行如下配置
@EnableCaching
@SpringBootApplication
@MapperScan(basePackages = “com.li.dao”)
public class LiApplication {
public static void main(String[] args) {
SpringApplication.run(LiApplication.class, args);
}
}
6.UserDaoTest类中添加如下配置
@Resource
private UserDao userDao;
7.首先创建RoleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> SELECT role_name FROM tb_users INNER JOIN tb_urs on tb_users.users_id=tb_urs.uid INNER JOIN tb_roles on tb_urs.rid=tb_roles.role_id where tb_users.username=#{username}8.创建RoleDao
public interface RoleDao {
public Set<String> queryRoleNameByUserName(String username) ;
}
9.创建RoleDaoTest
@RunWith(SpringRunner.class)
@SpringBootTest(classes = LiApplication.class)
public class RoleDaoTest {
@Resource
private RoleDao roleDao;
@Test
public void queryRoleNameByUserName() throws Exception {
Set<String> roleNames = roleDao.queryRoleNameByUserName("lisi");
Iterator<String> iterator = roleNames.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
10.首先创建PermissionMapper.xml、其次创建PerssionMapperDao接口
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
SELECT tb_permissions.permission_code FROM tb_users INNER JOIN tb_urs on tb_users.users_id=tb_urs.uid INNER JOIN tb_roles on tb_urs.rid=tb_roles.role_id INNER JOIN tb_rps on tb_roles.role_id=tb_rps.rid INNER JOIN tb_permissions on tb_rps.pid=tb_permissions.permission_id WHERE tb_users.username=#{username}
</select>
11.创建PermissionDaoTest
@RunWith(SpringRunner.class)
@SpringBootTest(classes = LiApplication.class)
public class PermissionDaoTest {
@Resource
private PermissionDao PermissionDao;
@Test
public void queryPermissionByUsername() throws Exception {
Set<String> ps = PermissionDao.queryPermissionByUsername("lisi");
Iterator<String> it = ps.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
12.进行权限配置
a. 获取认证安全数据、创建MyRealm、用户通过subject.login()登录之后调用此方法doGetAuthenticationInfo、最后把AuthenticationToken对象传递给principalCollection对象、然后从相应的对象之中获取用户名、然后查询权限列表
public class MyRealm extends AuthorizingRealm {
@Resource
private UserDao userDao;
@Resource
private RoleDao roleDao;
@Resource
private PermissionDao permissionDao;
public String getName(){
return "MyReal";
}
/*
* 获取授权的数据(将当前用户的角色及权限查询出来)
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户名
String username = (String) principalCollection.iterator().next();
//根据用户名获取角色列表
Set<String> roleNames = roleDao.queryRoleNameByUserName(username);
//根据用户名获取权限列表
Set<String> ps = permissionDao.queryPermissionByUsername(username);
System.out.println("查询权限信息");
//封装该用户的角色信息和权限信息并返回
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roleNames);
info.setStringPermissions(ps);
return info;
}
/*
-
获取认证的安全数据
-
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//authenticationToken就是subject.login(token)的token
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//根据用户名查询密码
User user = userDao.queryUserByUserName(username);
//多态写法封装对应的写法返回AuthenticationInfo、AuthenticationInfo传给principalCollection
// AuthenticationInfo info = new SimpleAuthenticationInfo(
// username,
// user.getUserPwd(),
// getName()
// );
//如加密加盐之后ByteSource.Util.bytes(user.getUserPwd()),
//23.ByteSource.Util.bytes(user.getPwdSalt())认证器知道盐后才能匹配
AuthenticationInfo info = new SimpleAuthenticationInfo(
username,
user.getUserPwd(),
ByteSource.Util.bytes(user.getPwdSalt()),
getName()
);
return info;
}
}b.showConfig类中通过过滤器设置权限如下
filterMapper.put("/c_add.html",“perms[sys:c:save]”);
c. 已注解的方式设置其权限
CustomerController中设置权限
@RequiresPermissions(“sys:k:find”)只用拥有该权限才能调用这个方法
d.CustimerControlle.class中自定义的权限
Subject subject = SecurityUtils.getSubject();
if(subject.isPermitted(“sys:k:find”)){
return “customer_list”;
}
System.out.println("--------->查询客户信息");
return “lesspermission”;
}
e. ShowConfig中进行配置
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
return authorizationAttributeSourceAdvisor;}
13.密码加密操作
a.创建UserServeiceImpl类
public void checkLogin(String username,String password,boolean rememberme) throws Exception{
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
token.setRememberMe(rememberme);
subject.login(token);
}
b.
c.
@RequestMapping(“regist”)
public String regist(String username,String password){
System.out.println(“注册”);
//注册时对密码加密存储
Md5Hash md5Hash = new Md5Hash(password);
System.out.println("---->"+md5Hash.toHex());
//加盐加密
int num = new Random().nextInt(90000)+10000;
Md5Hash md5Hash1 = new Md5Hash(password,num+"");
System.out.println(num+"---->"+md5Hash1.toHex());
//加盐加密多次hash
Md5Hash md5Hash2 = new Md5Hash(password,num+"",3);
System.out.println("---->"+md5Hash2);
//更牛hash
// SimpleHash simpleHash = new SimpleHash(“md5”,password,num+"",3);
// System.out.println(simpleHash.toHex());
return “login”;
}
d.添加regist.html
账号:
<p>
密码:<input type=" text" name="password">
</p>
<input type="submit" value="提交注册">
f. @Bean//指定加密规则 public HashedCredentialsMatcher getHashedCredentialsMatcher(){ //matcher就是用来指定加密规则的 HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); //加密方式 matcher.setHashAlgorithmName("md5"); //hash次数,如果加盐加密hash次数是多次则将hash次数进行改变 matcher.setHashIterations(1); return matcher; }
配置自定义Relam,myRealm.setCredentialsMatcher(matcher)加密工具给relam
@Bean
public MyRealm getMyRelam(HashedCredentialsMatcher matcher){
MyRealm myRealm = new MyRealm();
myRealm.setCredentialsMatcher(matcher);
return myRealm;
}
然后交给最后把MyRealem交给安全管理器
securityManager.setRealm(myRealm);
如果有盐则在MyRealm中的protected AuthenticationInfo doGetAuthenticationInfo中添加
AuthenticationInfo info = new SimpleAuthenticationInfo(
username,
user.getUserPwd(),
ByteSource.Util.bytes(user.getPwdSalt()),
getName()
);
添加盐加密规则 ByteSource.Util.bytes(user.getPwdSalt()),
14.缓存操作
添加缓存依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
a.index.html中添加如下操作.<shiro:hasPermission name=“sys:c:save”>
b.添加缓存配置文件ehcach1.xmls <?xml version="1.0" encoding="utf-8" ?>
c.ShowConfig中添加如下配置
/*
*25.切记缓存文件不能是ehcache.xml
-
1.ehCacheManager.setCacheManagerConfigFile(“classpath:ehcache.xml”);设置缓存配置文件
-
- securityManager.setRealm(myRealm);缓存管理器交给securityManager
-
*/
public EhCacheManager EhCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile(“classpath:ehcache1.xml”);
return ehCacheManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(EhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
securityManager.setRememberMeManager(getCookieRememberMeManager());
return securityManager;
}
/*
15.设置记住我
解释:登录时没有记住我,关闭浏览器之后,不可直接访问主界面,记住我则反之
a.登录后给后端控制器传入remenberme状态信息
@RequestMapping(“login”)
public String login(String username,String password,boolean remenberme){
try {
//26.传入remenberme参数
userService.checkLogin(username,password,remenberme);
System.out.println(“登录成功”);
return “index”;
}catch (Exception e){
System.out.println(“登录失败”);return "login"; }
}
d.UserServiceImple.class编写如下方法设置状态信息
public void checkLogin(String username,String password,boolean rememberme) throws Exception{
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
token.setRememberMe(rememberme);
subject.login(token);
}
b.ShowConfig中设置
public CookieRememberMeManager getCookieRememberMeManager(){
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
SimpleCookie cookie = new SimpleCookie(“rememberMe”);
cookie.setMaxAge(302460*60);
rememberMeManager.setCookie(cookie);
return rememberMeManager;
}
c.加入到security中
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRememberMeManager(getCookieRememberMeManager());
return securityManager;
}
16.多Realm
解释:
-
多realm的链式结构,用户名第一个realm中没有找到用户名和密码则会在第二个realm中找相应的用户名或者密码
-
第一个找到用户名和密码也会找第二个
a.自定义manageRealm
public class ManageRealm extends AuthorizingRealm {Logger log = LoggerFactory.getLogger(ManageRealm.class);
@Override
public String getName(){
return “ManageRealm”;
}@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; log.info("--------------------------->ManageRealm"); String username = token.getUsername(); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, "222222", getName()); return info;
}
}
b.自定义UserRealm
public class UserRealm extends AuthorizingRealm {Logger logger = LoggerFactory.getLogger(UserRealm.class);
@Override
public String getName(){
return “UserRealm”;
}@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("--------------->UserRealm");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, “123456”, getName());
return info;
}
}
c.ShiroConfig中进行相应的配置
public DefaultWebSecurityManager getDefaultWebSecurityManager(){
realms.add(userRealm());
realms.add(manageRealm());
securityManager.setRealms(realms);
return securityManager;
}
2.实现Realm并发结构
设置登录类型进行登录后,根据类型返回指定的realm
a.自定义Mytoken,重写UserNamePassword
public class Mytoken extends UsernamePasswordToken {
private String loginToken;
public Mytoken(String username,String password,String loginToken){
super(username, password);
this.loginToken = loginToken;
}
public String getLoginToken() {
return loginToken;
}
public void setLoginToken(String loginToken) {
this.loginToken = loginToken;
}
}
a.自定义认证器、重写认证方法
自定义认证器
public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
Logger logger = LoggerFactory.getLogger(MyModularRealmAuthenticator.class);
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("<-----------MyModularRealmAuthentication------------->");
this.assertRealmsConfigured();
//获得所有的Realm
Collection<Realm> realms = this.getRealms();
//自定义token
Mytoken token = (Mytoken) authenticationToken;
String loginToken = token.getLoginToken();
Collection<Realm> typeRealms=new ArrayList<>();
//输出realms中的Realm根据条件保存相应的Realm到typeRealms
for (Realm realm : realms) {
if(realm.getName().startsWith(loginToken)){
typeRealms.add(realm);
}
}
if(typeRealms.size()==1) {
//访问当个的realm
return this.doSingleRealmAuthentication((Realm) typeRealms.iterator().next(), authenticationToken);
}else{
//typeRealms这里传递的参数就是最终访问的realm
return this.doMultiRealmAuthentication(typeRealms,authenticationToken);
}
}
}
b.相应的UserController中进行相应的设置
public class UserController {
Logger logger = LoggerFactory.getLogger(UserController.class);
@RequestMapping("login")
public String login(String username,String password,String loginType){
logger.info("------------------------>UserController");
try {
// UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Mytoken mytoken = new Mytoken(username,password,loginType);
Subject subject = SecurityUtils.getSubject();
subject.login(mytoken);
return “index”;
}catch (Exception e){
return “login”;
}
}
}
b.ShiroConfig中自定义认证器交给spring容器
public MyModularRealmAuthenticator getMyModularRealmAuthenticator(){
MyModularRealmAuthenticator realmAuthenticator = new MyModularRealmAuthenticator();
return realmAuthenticator;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setAuthenticator(getMyModularRealmAuthenticator());
Collection<Realm> realms =new ArrayList<>();
realms.add(userRealm());
realms.add(manageRealm());
securityManager.setRealms(realms);
return securityManager;
}
注意(shiro4+shiro5框架demo)