在上一篇的基础上,本篇将增加shiro的授权管理和加密认证。代码也是基于上两篇。
shiro授权:
效果图:
在未授权时候直接跳转到未授权提示页面
首先在pom中增加导入thymeleaf扩展坐标
<!-- thymel对shiro的扩展坐标 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
使用Shiro内置过滤器拦截资源
设置授权过滤器 filterMap.put("/add", “perms[user:add]”);
注意:当前授权拦截后,shiro会自动跳转到未授权页面
设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录)可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
Map<String,String> filterMap = new LinkedHashMap<String,String>();
filterMap.put("/static/**", "anon");
filterMap.put("/tologin", "anon");
filterMap.put("/loginsubmit", "anon");
filterMap.put("/registe", "anon");
filterMap.put("/userRegister", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/add", "perms[user:add]");
filterMap.put("/update", "perms[user:update]");
//修改调整的登录页面
shiroFilterFactoryBean.setLoginUrl("/tologin");
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
//放最后
filterMap.put("/*", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
自定义Realm增加授权逻辑。
/**
* 自定义Realm
*
*
*/
public class UserRealm extends AuthorizingRealm{
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
info.addStringPermission("user:add");
return info;
}
html页面
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<html>
<head>
<meta charset="UTF-8">
<title>测试授权的使用</title>
</head>
<body>
<hr/>
<div shiro:hasPermission="user:add">
进入用户添加功能: <a href="add">用户添加</a><br/>
</div>
<div shiro:hasPermission="user:update">
进入用户更新功能: <a href="update">用户更新</a><br/>
</div>
</body>
</html>
好了到这里就完成了简单的授权过程,接下来开始完成加密的过程。
本篇使用的是MD5加密。
MD5
MD5使用:
@Test
public void Md5Test() {
// 对单个信息加密
Md5Hash md5 = new Md5Hash("123456");
System.out.println(md5.toString());
// 加密添加盐值 增大解密难度
md5 = new Md5Hash("123456","aaa");
System.out.println(md5.toString());
// 加密添加盐值 增大解密难度 5迭代五次
md5 = new Md5Hash("123456","aaa",5);
System.out.println(md5);
}
盐值的作用:
使用MD5存在一个问题,相同的password生成的hash值是相同的,如果两个用户设置了相同的密码,那么数据库中会存储两个相同的值,这是极不安全的,加Salt可以在一定程度上解决这一问题,所谓的加Salt方法,就是加点‘佐料’。其基本想法是这样的,当用户首次提供密码时(通常是注册时)由系统自动往这个密码里撒一些‘佐料’,然后在散列,而当用户登录时,系统为用户提供的代码上撒上相同的‘佐料’,然后散列,再比较散列值,来确定密码是否正确。
加盐的原理:给原文加入随机数生成新的MD5的值 。
Controller
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/index")
public String index(){
return "test";
}
@RequestMapping("/tologin")
public String tologin(){
return "login";
}
@RequestMapping("/registe")
public String register(){
return "registe";
}
@RequestMapping("/noAuth")
public String noAuth(){
return "/noAuth";
}
@RequestMapping("/towelcome")
public String inwelcome(){
return "welcome";
}
/**
* 登录逻辑处理
*/
@RequestMapping("/loginsubmit")
public String login(String username,String password,Model model){
/**
* 使用Shiro编写认证操作
*/
//1.获取Subject
Subject subject = SecurityUtils.getSubject();
//进行Md5加密,第一个参数为密码,第二参数是以用户名为盐,第三个参数是加密的次数
Md5Hash md5password=new Md5Hash( password, username,5);
System.out.println(md5password.toString());
//2.封装用户数据
//UsernamePasswordToken token = new UsernamePasswordToken(username,password);
UsernamePasswordToken token = new UsernamePasswordToken(username,md5password.toString());
//3.执行登录方法
try {
subject.login(token);
//登录成功
//跳转到test.html
return "redirect:/index";
} catch (UnknownAccountException e) {
//e.printStackTrace();
//登录失败:用户名不存在
System.out.println("用户名不存在");
model.addAttribute("msg", "用户名不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//e.printStackTrace();
//登录失败:密码错误
System.out.println("密码错误");
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/userRegister")
public String toregister(String username,String password,Model model)
{
//进行Md5加密,第一个参数为密码,第二参数是以用户名为盐,第三个参数是加密的次数
Md5Hash md5registepassword=new Md5Hash( password, username,5);
System.out.println(md5registepassword.toString());
User user=new User();
user.setUsername(username);
user.setPassword(md5registepassword.toString());
userService.register(user);
model.addAttribute("msg", "注册成功");
return "registe";
}
@RequestMapping("/add")
public String add(){
return "/user/add";
}
@RequestMapping("/update")
public String update(){
return "/user/update";
}
}
在这里就完成shiro的加密过程。
源码地址:https://gitee.com/jzzhu123456/shiroHouse_asd