4.SpringBoot+Shiro免密登录
一、查看原有的代码
首先我们看一下Shiro原有的账号密码登录关键代码,分析一下该如何改造,
Subject currentUser = ShiroKit.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray());
从这两行代码看出,我们需要重写一个获得Token的方法。
二、改造
1.新建一个枚举类,这个也可以不建立,因为我这边的系统免密登录和账号密码登录的情况有存在,所以我加了一个枚举类进行判断,用户具体执行哪一个登录方法。
枚举类具体代码如下:
package com.stylefeng.guns.core.shiro.secretfree;
/**
* 登录类型枚举类
*/
public enum LoginType {
PASSWORD("password"), // 密码登录
NOPASSWD("nopassword"); // 免密登录
private String code;// 状态值
private LoginType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
2.新建自定义的UserRealem类继承AuthorizingRealm
package com.stylefeng.guns.core.shiro;
import com.stylefeng.guns.core.shiro.ShiroUser;
import com.stylefeng.guns.core.shiro.factory.IShiro;
import com.stylefeng.guns.core.shiro.factory.ShiroFactroy;
import com.stylefeng.guns.core.shiro.secretfree.CustomeToken;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.system.model.User;
import com.stylefeng.guns.modular.system.service.IUserService;
import org.apache.shiro.authc.*;
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 java.util.HashSet;
import java.util.List;
import java.util.Set;
public class UserRealm extends AuthorizingRealm {
@Autowired
private IUserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
IShiro shiroFactory = ShiroFactroy.me();
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
List<Integer> roleList = shiroUser.getRoleList();
Set<String> permissionSet = new HashSet<>();
Set<String> roleNameSet = new HashSet<>();
for (Integer roleId : roleList) {
List<String> permissions = shiroFactory.findPermissionsByRoleId(roleId);
if (permissions != null) {
for (String permission : permissions) {
if (ToolUtil.isNotEmpty(permission)) {
permissionSet.add(permission);
}
}
}
String roleName = shiroFactory.findRoleNameByRoleId(roleId);
roleNameSet.add(roleName);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissionSet);
info.addRoles(roleNameSet);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
//增加免密登录功能,使用自定义token
CustomeToken token = (CustomeToken) authcToken;
IShiro shiroFactory = ShiroFactroy.me();
String loginId = (String)token.getPrincipal();
//先判斷 这个token还是否有效
User user = userService.getByAccount(loginId);
if(user == null) {
throw new UnknownAccountException();
}
if(user.getStatus() != 1) {
throw new LockedAccountException();
}
// User user = shiroFactory.user(token.getUsername());
ShiroUser shiroUser = shiroFactory.shiroUser(user);
SimpleAuthenticationInfo authenticationInfo = shiroFactory.info(shiroUser, user, getName());
return authenticationInfo;
}
/**
为了防止出现AuthenticationException 异常覆盖的问题,每个realm中加入support方法
*/
@Override
public boolean supports(AuthenticationToken var1){
return var1 instanceof CustomeToken;
}
}
3.修改ShiroUser 类的代码
package com.stylefeng.guns.core.shiro;
import java.io.Serializable;
import java.util.List;
/**
* 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息
*
*
*/
public class ShiroUser implements Serializable {
private static final long serialVersionUID = 1L;
public Integer id; // 主键ID
public String account; // 账号
public String name; // 姓名
public Integer deptId; // 部门id
public List<Integer> roleList; // 角色集
public String deptName; // 部门名称
public List<String> roleNames; // 角色名称集
private String station;//岗位
private String spaccount;//上级工号
private String spname;//上级姓名
private Integer astauts;//考核/非考核 1考核 2非考核
private String view;//有权查看的人员
public String getView() {
return view;
}
public void setView(String view) {
this.view = view;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public List<Integer> getRoleList() {
return roleList;
}
public void setRoleList(List<Integer> roleList) {
this.roleList = roleList;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<String> getRoleNames() {
return roleNames;
}
public void setRoleNames(List<String> roleNames) {
this.roleNames = roleNames;
}
//新增字段
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
public String getSpaccount() {
return spaccount;
}
public void setSpaccount(String spaccount) {
this.spaccount = spaccount;
}
public String getSpname() {
return spname;
}
public void setSpname(String spname) {
this.spname = spname;
}
public Integer getAstauts() {
return astauts;
}
public void setAstauts(Integer astauts) {
this.astauts = astauts;
}
@Override
public String toString() {
return "ShiroUser{" +
"id=" + id +
", account='" + account + '\'' +
", name='" + name + '\'' +
", deptId=" + deptId +
", roleList=" + roleList +
", deptName='" + deptName + '\'' +
", roleNames=" + roleNames +
", station='" + station + '\'' +
", spaccount='" + spaccount + '\'' +
", spname='" + spname + '\'' +
", astauts=" + astauts +
'}';
}
}
4.修改ShiroDBRealm类的代码
package com.stylefeng.guns.core.shiro;
import com.stylefeng.guns.core.shiro.factory.IShiro;
import com.stylefeng.guns.core.shiro.factory.ShiroFactroy;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.system.model.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ShiroDbRealm extends AuthorizingRealm {
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
throws AuthenticationException {
IShiro shiroFactory = ShiroFactroy.me();
//免密登陆新增代码
//CustomeToken token = (CustomeToken) authcToken;
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
User user = shiroFactory.user(token.getUsername());
ShiroUser shiroUser = shiroFactory.shiroUser(user);
//原先的代码
SimpleAuthenticationInfo info = shiroFactory.info(shiroUser, user, super.getName());
return info;
}
/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
IShiro shiroFactory = ShiroFactroy.me();
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
List<Integer> roleList = shiroUser.getRoleList();
Set<String> permissionSet = new HashSet<>();
Set<String> roleNameSet = new HashSet<>();
for (Integer roleId : roleList) {
List<String> permissions = shiroFactory.findPermissionsByRoleId(roleId);
if (permissions != null) {
for (String permission : permissions) {
if (ToolUtil.isNotEmpty(permission)) {
permissionSet.add(permission);
}
}
}
String roleName = shiroFactory.findRoleNameByRoleId(roleId);
roleNameSet.add(roleName);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissionSet);
info.addRoles(roleNameSet);
return info;
}
/**
* 设置认证加密方式
*/
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();
md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);
md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);
super.setCredentialsMatcher(md5CredentialsMatcher);
}
/**
为了防止出现AuthenticationException 异常覆盖的问题,每个realm中加入support方法
*/
@Override
public boolean supports(AuthenticationToken var1){
return var1 instanceof UsernamePasswordToken;
}
}
5.修改Login的具体方法
Subject currentUser = ShiroKit.getSubject();
//增加免密登录功能,使用自定义token
CustomeToken customeToken = new CustomeToken(username);
currentUser.login(customeToken);
ShiroUser shiroUser = ShiroKit.getUser();
super.getSession().setAttribute("shiroUser", shiroUser);
super.getSession().setAttribute("username", shiroUser.getAccount());
//登录日志记录
//LogManager.me().executeLog(LogTaskFactory.loginLog(shiroUser.getId(), getIp()));
ShiroKit.getSession().setAttribute("sessionFlag", true);
6.到此,Shiro免密登录改造完成。