《一,认证》数据库
1.先建两个class文件session
一个写 AuthRealm (受权与认证方法,并继承) extends AuthorizingRealm app
获取其默认方法doGetAuthorizationInfo(受权方法) doGetAuthenticationInfo(认证方法) jsp
一个写PasswordMatcher(密码验证器,并继承) extends SimpleCredentialsMatcheride
获取默认方法doCredentialsMatch 工具
2.在Action的登陆方法中 ui
@Action("loginAction_login")//重页面跳转过来的路径名加密
public String login() throws Exception {对象
//判断用户名是否是为空,若是是说明没有登陆,跳转到用户登陆页面blog
if(UtilFuns.isEmpty(username)){
return "login";
}
//1.SecurityUtils:是shiro的一个工具类。经过SecurityUtils获取getSubject 获得一个返回值
Subject subject = SecurityUtils.getSubject();
//3.根据逻辑2。new一个 UsernamePasswordToken,并传上用户名及密码。把返回值传给登入做为条件。
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
//2. subject的返回值里有两个方法logout:登出 login:登入。这里咱们使用登陆方法,经过方法咱们能够看到须要一个返回值:AuthenticationToken的类型,又由于AuthenticationToken 是一个接口,因此咱们使用他下面的UsernamePasswordToken 的实现类来写(ps:查看方法:Ctrl+t),
subject.login(token);//当调用subject的登入方法时,会跳转到认证的方法上。。。。。。。。。。
//4.在证方法中subject已经把获取到了用户,因此咱们用subject.getPrincipal 能够获取到登陆的用户,Principal:他是在认证方法中的principal:主要对象(登陆的用户,详情看认证方法return的哪一步注释)
User user = (User) subject.getPrincipal();
//5.把user用户数据经过Session.put放在session值栈中。SysConstant.CURRENT_USER_INFO:是一个返回的值,在jsp页面中能够接收到,也能够直接写一个字符串让页面接收,返回的数据能够在页面作回显等功能
session.put(SysConstant.CURRENT_USER_INFO, user);
return SUCCESS;//以上所有都过了后,让其访问页面数据
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
super.put("errorInfo", "您的用户名或密码错误"); //登陆页面的错误信息提示
return "login";
}
}
//退出
@Action("loginAction_logout")
public String logout(){
session.remove(SysConstant.CURRENT_USER_INFO); //删除session
SecurityUtils.getSubject().logout(); //调用登出方法
return "logout";
}
3.在认证方法中的doGetAuthenticationInfo
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
// TODO Auto-generated method stub
System.out.println("调用认证方法");
UsernamePasswordToken token =(UsernamePasswordToken)arg0;//先将arg0强转为UsernamePasswordToken类型
final String username = token.getUsername();//经过token获取到用户名
Specification<User> spec = new Specification<User>() { //把username 设为查询条件,查询数据库是否有这个用户名
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
// TODO Auto-generated method stub
return cb.equal(root.get("username").as(String.class),username);
}
};
List<User> find = userServiceimpl.find(spec); //把spec 条件放到 查询中查询数据 查询用户名
if(find!=null&& find.size()>0){ //判断返回的结果不为空,及返回的数不小于0
User user = find.get(0); //经过索引获取到返回值的第一个数中的数据
return new SimpleAuthenticationInfo(user, user.getPassword(), getName()) ;//这里若是上面的都成立后会return到密码校验哪里去
/* SimpleAuthenticationInfo:是doGetAuthenticationInfo的一个实现类,由于doGetAuthenticationInfo 是一个接口不能直接new
把返回值添加到条件中 //principal:主要对象(登陆的用户) , credentials:密码 ,realm的名字能够经过getName获取类名做为区分 */
}
return null;
}
4.在密码检验中PasswordMatcher
public class PasswordMatcher extends SimpleCredentialsMatcher { //先实现一个接口SimpleCredentialsMatcher 获取doCredentialsMatch的内部方法
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
System.out.println("调用了密码对比器");
UsernamePasswordToken utoken = (UsernamePasswordToken) token;
/*[把AuthenticationToken 中的token 装换为AuthenticationToken 中的(ps:查看方法Ctrl+t)
UsernamePasswordToken实现类 由于AuthenticationToken 是接口不能new数据],*/
String pwd = new String(utoken.getPassword());//经过utoken 获取用户密码,并转换成String类型,注意这里的转换不能强转,要用new的方法
//source:要加密的内容 salt:增长复杂度的内容 哈希次数:2
Md5Hash md5Hash = new Md5Hash(pwd, utoken.getUsername(), 2); //调用Md5加密 为输入的数据加密
String credentials = (String)info.getCredentials(); //经过AuthenticationInfo 的info 查询数据库的密码 装换成String类型
return equals(md5Hash.toString(),credentials); //对比用户输入的数据和数据库密码是否一致。return走,返回到Action方法中。
}
}
5.执行流程图
《二,受权》
1.在受权方法中
@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("受权"); SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo(); Set<String> permissionSet = new HashSet<>(); Set<String> roleNameSet = new HashSet<>(); ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal(); List<Integer> roleList = shiroUser.getRoleList(); for (Integer roleId : roleList) { List<String> permissions = roleMenuMapper.findPermissionsByRoleId(roleId); if (permissions != null) { for (String permission : permissions) { if (StringUtils.isNotEmpty(permission)) { permissionSet.add(permission); } } } String roleName = roleMapper.findRoleNameByRoleId(roleId); roleNameSet.add(roleName); } simpleAuthorizationInfo.addStringPermissions(permissionSet); simpleAuthorizationInfo.addRoles(roleNameSet); //查询登陆用户的全部角色的权限 return simpleAuthorizationInfo;}