明天的太阳

导航

【shop-2】使用shiro实现登录

本次commit代码

引入依赖

引入shiro

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.5.3</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>

或者

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.11.0</version>
</dependency>

增加MyBatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- 使用驼峰命名法转换字段。 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <typeAlias alias="Integer" type="java.lang.Integer"/>
        <typeAlias alias="Long" type="java.lang.Long"/>
        <typeAlias alias="HashMap" type="java.util.HashMap"/>
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
        <typeAlias alias="ArrayList" type="java.util.ArrayList"/>
        <typeAlias alias="LinkedList" type="java.util.LinkedList"/>
    </typeAliases>

    <mappers>
        <mapper resource="db/mybatis/UserMapper.xml"/>
    </mappers>

</configuration>

配置application.properties

这里我们改为application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:port/databasename?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
    username: yourusername
    password: yourpassword
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  config-location: classpath:db/mybatis/config.xml

配置Shiro

Realm

@Service
public class ShiroRealm extends AuthorizingRealm {
    private VerificationCodeCheckService verificationCodeCheckService;

    @Autowired
    public ShiroRealm(VerificationCodeCheckService verificationCodeCheckService) {
        this.verificationCodeCheckService = verificationCodeCheckService;
        this.setCredentialsMatcher(new CredentialsMatcher() {
            @Override
            public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
                return new String((char[]) authenticationToken.getCredentials()).equals(authenticationInfo.getCredentials());
            }
        });
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String tel = (String) authenticationToken.getPrincipal();
        String correctCode = verificationCodeCheckService.getCorrectCode(tel);
        return new SimpleAuthenticationInfo(tel, correctCode, getName());
    }
}

ShiroConfig

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        Map<String, String> map = new HashMap<>();
        map.put("/api/code", "anon");
        map.put("/api/login", "anon");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(ShiroRealm realm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(realm);
        manager.setCacheManager(new MemoryConstrainedCacheManager());
        manager.setSessionManager(new DefaultSessionManager());
        SecurityUtils.setSecurityManager(manager);
        return manager;
    }
}

Controller

@RestController
@RequestMapping("/api")
public class AuthController {
    private AuthService authService;

    @Autowired
    public AuthController(AuthService authService) {
        this.authService = authService;
    }

    @GetMapping("/code")
    public User sendCode(@RequestParam String tel) {
        return authService.sendVerificationCode(tel);
    }

    @PostMapping("/login")
    public User login(@RequestBody TelAndCode telAndCode) {
        // https://shiro.apache.org/authentication.html
        UsernamePasswordToken token = new UsernamePasswordToken(telAndCode.getTel(), telAndCode.getCode());
        token.setRememberMe(true);

        Subject currentUser = SecurityUtils.getSubject();
        currentUser.login(token);
        return null;
    }
}

小插曲

  1. Spring6 使用了java17,在此之前你如果安装了java8,那么环境变量中的C:\ProgramData\Oracle\Java\javapath会让你的新配置不生效,删掉即可。
  2. 运行时javax.servlet.filter找不到

引入依赖解决。

<dependency>
	<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
	<version>4.0.1</version>
</dependency>
  1. 报错Result Maps collection already contains value for xxx.yyyResultMap

原因是在application.yml

mybatis:
  mapper-locations: classpath:db/mybatis/UserMapper.xml

和mybatis的config.xml

<mappers>
    <mapper resource="db/mybatis/UserMapper.xml"/>
</mappers>

重复配置了UserMapper.xml,删除其一。

posted on 2023-02-14 22:20  东方来客  阅读(20)  评论(0编辑  收藏  举报