首先感谢慕课网的老师,让我受益匪浅
https://www.imooc.com/video/16961
整体源码
github地址:https://github.com/binlian/binglian-shiroLoginResit
实现了登录才可以访问其他网站,
实现了管理员的权限以及用户的权限,
我先总结一下所学的
我这里借用一下老师的图片
上面的C/C++、PHP这些都其实是主体subject 传过来
然后传给security Manager 在manager中又有认证,授权,会话这些
我们先看认证 subject 传给authenticator 然后传给Realms 而Realms 去调用数据库或者文本里面的数据进行验证()
授权一样,也是anthorizer 然后调用Realms 然后在掉数据库或文本
视频也详细介绍了 我会贴在整体架构里的最下面
shiro认证
shiro授权
然后我们再说下三个Realm
iniRealm 是文档 他获取文本里面的数据进行认证授权,
JDBCRealm 是从数据库中获取
自定义可以模拟数据库,也可以从数据库 自定义
我学习的github地址:https://github.com/binlian/shiro
首先我们看下目录
config就是配置shiro
controller 不多说 控制层
mapper和pojo是dao层和实体类 因为我这里使用的mybatis逆向工程
serviceImpl这里面是接口实现层 我Realm自定就放在这下面
数据库的创建
create table user(
id int(32) not null auto_increment,
username varchar(32) not null ,
password varchar(32) not null,
rolse enum('admin','user') not null default 'user',
primary key(id)
)
然后我们先看下Dao和xml
这userMapper 继承工具类
这里声明接口在xml实现,为了让Realm获取 password和rolse进行认证和授权
package com.binglian.mapper;
import com.binglian.pojo.User;
import com.binglian.utils.MyMapper;
public interface UserMapper extends MyMapper<User> {
//根据username返回password
String getUserPassword(String username);
//根据username返回rolse
String getUserRolse(String username);
}
<?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" >
<mapper namespace="com.binglian.mapper.UserMapper" >
<resultMap id="BaseResultMap" type="com.binglian.pojo.User" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<result column="rolse" property="rolse" jdbcType="CHAR" />
</resultMap>
<select id="getUserPassword" parameterType="String" resultType="String">
select password from user where username=#{username}
</select>
<select id="getUserRolse" parameterType="String" resultType="String">
select rolse from user where username=#{username}
</select>
</mapper>
然后就是service接口和实现层了
package com.binglian.service;
public interface UserService {
/**
* 根据username 查询密码
* @param username
* @return
*/
String loginPassword(String username);
/**
* 根据username查询角色
* @param username
* @return
*/
String queryRolse(String username);
/**
* 注册
* @param username
* @param password
*/
void regist(String username,String password);
}
package com.binglian.service.impl;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.binglian.mapper.UserMapper;
import com.binglian.pojo.User;
import com.binglian.service.UserService;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserMapper userMapper;
@Override
public String loginPassword(String username) {
String password=userMapper.getUserPassword(username);
return password;
}
@Override
public String queryRolse(String username) {
String rolse=userMapper.getUserRolse(username);
return rolse;
}
@Override
public void regist(String username, String password) {
User user=new User();
// 将用户名作为盐值
ByteSource salt = ByteSource.Util.bytes(username);
/**
* 第一个参数 加密方式
* 第二是密码
* 第三个是盐值
* 第四个是加密次数
* 然后把变为String型
*/
String newpassword = new SimpleHash("MD5", password, salt, 1024).toHex();
user.setId(null);
user.setPassword(newpassword);
user.setUsername(username);
user.setRolse("admin");
userMapper.insert(user);
}
}
然后就是我们的自定义Realm
我们从数据库中获取密码和rolse 进行认证,和授权
Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
Principal:身份信息
是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
package com.binglian.service.impl;
import static org.hamcrest.CoreMatchers.nullValue;
import java.util.Set;
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.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import com.binglian.service.UserService;
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权管理
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//从主体获取用户
String username=(String)principals.getPrimaryPrincipal();
//从数据库查询用户的角色
String rolse=userService.queryRolse(username);
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRole(rolse);
return simpleAuthorizationInfo;
}
/**
* 认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//从主体获取传过来的用户
String username=(String)token.getPrincipal();
//通过用户传过来从数据库进行密码
String password=userService.loginPassword(username);
if(password == null){
return null;
}
//加盐
ByteSource salt = ByteSource.Util.bytes(username);
String realmName = this.getName();//获取当前自定义的realm
SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(username, password, salt, realmName);
return simpleAuthenticationInfo;
}
}
然后再是shiro配置
Bean一定要加 加入spring容器
当时在@RequiresRoles("admin")无效,需要在里面加两个配置 仔细看配置 这个是授权管理
package com.binglian.config;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.binglian.service.impl.CustomRealm;
@Configuration
public class ShiroConfig {
/**
* 1.构建securityManager环境
DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
defaultSecurityManager.setRealm(customRealm);
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();//加密配置
matcher.setHashAlgorithmName("MD5");//使用算法md5
matcher.setHashIterations(1);//加密次数
customRealm.setCredentialsMatcher(matcher);//对自定义Realm进行加密配置
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器。匹配原则是最上面的最优先匹配
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
// 配置不会被拦截的链接
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/regist", "anon");
filterChainDefinitionMap.put("/regist1", "anon");
filterChainDefinitionMap.put("/login1", "anon");
// 剩余请求需要身份认证
filterChainDefinitionMap.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// // 登录成功后要跳转的链接
// shiroFilterFactoryBean.setSuccessUrl("/index");
//
// //未授权界面;
// shiroFilterFactoryBean.setUnauthorizedUrl("/403");
// shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public CustomRealm myShiroRealm(HashedCredentialsMatcher matcher){
CustomRealm myShiroRealm = new CustomRealm();
myShiroRealm.setCredentialsMatcher(matcher);
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(HashedCredentialsMatcher matcher){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm(matcher));
return securityManager;
}
/**
* 密码加密配置
* 加密次数
* 并给realm
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 采用MD5方式加密
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
// 设置加密次数
hashedCredentialsMatcher.setHashIterations(1024);
return hashedCredentialsMatcher;
}
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
* @return
*/
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/**
* 开启aop注解支持
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
然后也就是最后一个 控制层
package com.binglian.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.binglian.service.UserService;
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/login")
@ResponseBody
public String login(@RequestParam("username") String username,
@RequestParam("password") String password){
Subject subject=SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(username, password);
try {
subject.login(token);
if (subject.isAuthenticated()==true) {
System.out.println("成功");
}
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println(e);
}
if (subject.hasRole("admin")) {
return "admin权限";
}
return "无admin";
}
@RequestMapping("/regist")
@ResponseBody
public String regist(@RequestParam("username") String username,
@RequestParam("password") String password){
userService.regist(username, password);
return "注册成功";
}
@RequestMapping("/list")
public String list(){
return "list";
}
@RequiresRoles("admin")
@RequestMapping("/add")
@ResponseBody
public String add(){
return "admin";
}
@RequiresRoles("user")
@RequestMapping("/add1")
@ResponseBody
public String add1(){
return "用户";
}
@RequestMapping("/regist1")
public String registindex(){
return "regist";
}
@RequestMapping("/login1")
public String loginindex(){
return "login";
}
}
github地址:https://github.com/binlian/binglian-shiroLoginResit