("/test1
public class ShiroRealm extends AuthorizingRealm {
@Autowired
SysUsersDao sysUsersDao;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.获取用户登录时提交的用户名
UsernamePasswordToken uToken=(UsernamePasswordToken)authenticationToken;
//获取用户名
String name = uToken.getUsername();
//2.基于用户名查询用户信息并校验
//@Select("select * from sys_users where username=#{username}")
//SysUsers selectUserByUsername(String username);
SysUsers sysUsers = sysUsersDao.selectUserByUsername(name);
//未知账户异常
if(sysUsers==null)throw new UnknownAccountException();
//锁定账户异常(账号禁用)
if(sysUsers.getValid()==0)throw new LockedAccountException();
//3.封装查询到的用户信息并返回(交给调用者)
//ByteSource对盐做一个编码处理
ByteSource credentialsSalt = ByteSource.Util.bytes(sysUsers.getSalt());
SimpleAuthenticationInfo info =
new SimpleAuthenticationInfo(
sysUsers,//principal 表示登录用户身份
sysUsers.getPassword(),//hashedCredentials 数据库中已加密的密码
credentialsSalt,//加密盐,ByteSource对盐值对象的处理
this.getName()//realmName
);
return info;//将封装好的数据交给securityManager进行认证
}
}
2.2 获取凭证匹配器
@Override
public CredentialsMatcher getCredentialsMatcher( ) {
//创建密码匹配器对象
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//设置加密算法
matcher.setHashAlgorithmName("MD5");
//设置加密次数
matcher.setHashIterations(1);
return matcher;
}
2.3 获取授权信息并封装(认证功能测试完毕再实现此操作)
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//1.获取登录用户信息
SysUsers user= (SysUsers) principalCollection.getPrimaryPrincipal();
//2.基于登录用户获取用户权限(根据用户id去数据库查询到当前用户权限)
//@RequiresPermissions("sys:user:update")用在service实现类的方法上
//框架会拿着set中的授权标识和注解中的参数比较
//如果set中存在才能执行方法
Set set= sysMenuDao.selectUserPermissions(user.getId());
//3.封装用户权限并返回
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.setStringPermissions(set);
return info;
}
3.创建shiro配置类
3.1返回刚刚自己创建的Realm对象
@Configuration
public class MyShiroConfig {
@Bean
public Realm realm(){
return new ShiroRealm();
}
}
3.2 定义过滤规则 官网链接https://shiro.apache.org/web.html
anon,logout,authc,user…这些是shiro框架指定的过滤规则
(“/test1
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition(){
//过滤链对象的定义(这个过滤链中包含了很多内置过滤器)
DefaultShiroFilterChainDefinition chainDefinition=
new DefaultShiroFilterChainDefinition();
//指定过滤链中的过滤规则,例如: (放行要在认证之前)
//配置/test1
@Bean
public RememberMeManager rememberMeManager(){
CookieRememberMeManager cManager=new CookieRememberMeManager();
//默认记住用户信息 cookie的名字叫rememberMe
SimpleCookie cookie=new SimpleCookie("rememberCGB");
cookie.setMaxAge(7*24*60*60);//七天
cManager.setCookie(cookie);
//设置加密解密密钥
//(不配置是默认自己生成密钥对用户信息进行加密解密,这样的话你使用"记住我"时当你服务器重启就会再次重新生成密钥,
// 用新的密钥解密之前cookie中的密钥就会报错无法解密)
//记住我的cookie会加密,加上此配置会固定用这个加密key加密和解密(Encode)
cManager.setCipherKey(Base64.decode("6ZmI612j51+R5aSn5201AA=="));
return cManager;
}
3.4 配置session管理器对象
@Bean
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
//session的超时时间
// sessionManager.setGlobalSessionTimeout(1000*60*60);//1个小时
sessionManager.setGlobalSessionTimeout(2*60*1000);//2分钟
//删除无效session
sessionManager.setDeleteInvalidSessions(true);
//当客户端cookie被禁用是否要设置url重写(默认为true)
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
3.5 解决@RequiresPermissions用在controller层导致@GetMapper.@PostMapper…等注解失效的问题
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator proxyCreator=new DefaultAdvisorAutoProxyCreator();
//下面两个方法都可以使注解生效
proxyCreator.setProxyTargetClass(true);//让目标对象上的注解映射生效
// proxyCreator.setUsePrefix(true);
return proxyCreator;
}
4.测试认证授权功能
4.1 认证功能
JsonResult是自己封装的类,用于服务端响应到客户端的数据(文章最后有添加这个类的代码)
@GetMapping("/{username}/{password}")
public JsonResult doUpdatePassword(@PathVariable String username,
@PathVariable String password){
//获取shiro中的Subject对象,基于此对象提交用户信息
Subject subject = SecurityUtils.getSubject();
//执行登录(将用户名和密码提交给securityManager)
UsernamePasswordToken token =
new UsernamePasswordToken(username, password);
//用户登录时通过设置token对象设置记住我
token.setRememberMe(true);
subject.login(token);
return new JsonResult("登录 ok");
}
4.2 授权功能
为service方法加@RequiresPermissions(“sys:user:update”)
"sys:user:update"为shiro授权信息的固定格式
@RequiresPermissions("sys:user:update")
public int validById(Integer id, Integer valid) {
int rows=sysUserDao.validById(id,valid,"admin");//这里的admin为假数据,后续为登录用户
if(rows==0)
throw new RestClientException("记录可能不存在了");
return rows;
}
5.配置全局异常处理
@RestControllerAdvice(annotations = RestController.class)
public class RestControllerExceptionHandler {
public static final Logger log =
LoggerFactory.getLogger(RestControllerExceptionHandler.class);
@ExceptionHandler(RuntimeException.class)
public JsonResult bdoHandleRuntimeException(RuntimeException e) {
e.printStackTrace();
log.error("exception msg is {}",e.getMessage());
return new JsonResult(e);
}
public JsonResult doShiroException(ShiroException e){
e.printStackTrace();
JsonResult r=new JsonResult();
r.setState(0);
if (e instanceof UnknownAccountException){
r.setMessage("账户不存在");
}else if (e instanceof IncorrectCredentialsException){
r.setMessage("密码不正确");
}else if (e instanceof LockedAccountException){
r.setMessage("账户被锁定");
}else if (e instanceof AuthorizationException){
r.setMessage("没有权限");
}else{
r.setMessage("认证或授权失败");
}
return r;
}
}
JsonResult代码
public class JsonResult {
private Integer state=1;//1 表示OK,0表示Error
private String message="ok";
private Object data;
public JsonResult(){}
public JsonResult(String message){
this.message=message;
}
public JsonResult(Integer state, String message){
this(message);
this.state=state;
}
public JsonResult(Object data){//new JsonResult(list)
this.data=data;
}
//当出现异常时,可以通过此构造方法对异常信息进行封装
public JsonResult(Throwable exception){//new JsonResult(exception);
this(0,exception.getMessage());
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}