Springboot整合Shiro实现登录验证

Springboot整合Shiro实现登录验证

1 关于Shiro

Apache Shiro 是一个Java的安全框架,主要有三个核心的组件:

  1. Subject:指当前的操作用户。
  2. SecurityManager:安全管理器,Shiro通过它来管理内部组件。
  3. Realm:用于权限的验证,需要自己实现。

2 步骤

首先引入Shiro的maven:

<!--整合shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.4.0</version>
</dependency>

application.properties里添加Shrio的配置信息:

#1.第一行表示是否允许将sessionld 放到cookie shiro.sessionManager.sessionIdCookieEnabled=true

  #2第二行表示是否允许将sessionld 放到Url地址拦中

  shiro.sessionManager.sessionIdUrlRewritingEnabled=true

  #3.第三行表示访问未获授权的页面时,默认的跳转路径

  shiro.unauthorizedUrl=/login

  #4.第四行表示开启shiro

  shiro.web.enabled=true

  #5.第五行表示登录成功的跳转页面

  shiro.successUrl=/index

  #6.第六行表示登录页面

  shiro.loginUrl=/doLogin

需要实现一个Realme类,继承AuthorizingRealm,并实现它的方法,其中一个是AuthorizationInfo,需要自己写对于权限的管理,另一个是AuthenticationInfo,这里是写登录验证。具体代码如下:

public class UserRealm extends AuthorizingRealm {

    @Autowired

    private StudentServiceImpl studentService;
    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        return null;

    }

  

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String username = authenticationToken.getPrincipal().toString();

        Optional<Student> studentOptional = studentService.findStudentBySno(username);

        if (studentOptional.isPresent()) {

            Student student = studentOptional.get();

            return new SimpleAuthenticationInfo(username, student.getPassword(), ByteSource.Util.bytes(username), getName());

}

        throw new UnknownAccountException("不存在");

    }

}

登录验证是先获取到username,然后查到该用户的相关信息,如果不存在则返回一个UnknownAccountException异常。存在则返回一个SimpleAuthenticationInfo,参数是username、数据库查到的密码、还有盐值和用户名。接着需要配置Shiro:

@Configuration

  public class ShiroConfig {

    @Bean

    UserRealm userRealm() {

        return new UserRealm();

    }

  

    @Bean

    DefaultWebSecurityManager securityManager() {

        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        defaultWebSecurityManager.setRealm(userRealm());

        return defaultWebSecurityManager;

    }

  

    @Bean

    ShiroFilterChainDefinition shiroFilterChainDefinition() {

        DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();

        defaultShiroFilterChainDefinition.addPathDefinition("/doLogin", "anon");

        defaultShiroFilterChainDefinition.addPathDefinition("/**", "authc");

        return defaultShiroFilterChainDefinition;

    }

}

 

将刚刚的UserReaml交给SecurityManager进行管理。并且设置过滤器,比如哪些接口是需要登录后或者某种权限才能访问的。其中 anon 表示匿名即游客就能访问,这里设置了登录接口。authc是需要登录验证后才能访问。除了这两种还有其他:authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user。如果用户开启了RememberMe,则当用户关闭浏览器,下次访问时,不再是authc,而是user。因为authc是需要重新认证的。User就表示该用户曾经被Shiro记住过。

接下来写LoginController:

@PostMapping("/doLogin")

  public Result<Object> doLogin(@RequestBody UserToken userToken) {

    Subject subject = SecurityUtils.getSubject();

    String pwd = ShiroKit.mds(String.valueOf(userToken.getPassword()), userToken.getUsername());

    UsernamePasswordToken token = new UsernamePasswordToken(userToken.getUsername(), pwd);

    String sessionId = (String) subject.getSession().getId();

    try {

        subject.login(token);

        Map<String, String> map = new HashMap<String, String>();

        map.put("sessionId", sessionId);

        map.put("username", userToken.getUsername());

        return common.SUCCESS(map);

    } catch (Exception e) {

        return common.ERROR(codeEnum.getERR_PWD(), "用户名或密码错误", "");

    }

}

因为密码不是明文储存在数据库中的,所以这里采用了MD5加密,没有使用Shiro的加密方式。需要将获取到的密码进行再次加密后和数据库进行比对验证。

加密方式:

public class ShiroKit {

    public static String mds(String password, String salt) {

  

        return new Md5Hash(password, salt, 1).toHex();//  加密一次

    }

}

这里subject.login则会调用UserReaml,将用户名和加密后的密码传过去进行验证。如果有错误,比如密码不正确或者用户不存在就给前端返回一个用户名或密码不正确的提示。

登出:

@GetMapping("/logout")

  public Result logout() {

    SecurityUtils.getSubject().logout();

    return common.SUCCESS("");

}

3 总结

这里只是简单运用了shiro实现了登录验证。没有去分析源码,有需要的朋友可以自行去官方查阅。

 

 

 

 

 

 

 

刘玉江

2020年09月27日

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值